A way to convince git to fetch a bundle into an active branch?

Viewed 334

I have a central repo with, say, three branches, branchA, branchB, and branchC. I make some commits in, say, branchB. Then I need to copy the commits to another platform that I can't reach over a network. So I make a bundle. The last bundle I made was at, say, commit 123456f. So I create my bundle by:

> git bundle create myrepo.bundle 123456f..HEAD

Now, remembering that this was done on branchB, at my other platform, if I have checked out branchB, I try to incorporate the changes in the bundle with

> git fetch myrepo.bundle HEAD:branchB

but I am told

fatal: Refusing to fetch into current branch refs/heads/replace_pipeline_codes of non-bare repository

I can fix this by checking out out branchA (or C) instead, and running the same fetch command from there. But this is awkward and immediately raises the question of what do I do if I have a repo with only one branch?

So what do I do in that case, and is there a way to convince git to fetch a bundle into an active branch?

By the way, this is similar to this question, but in that question there is no mention of bundling, so I don't see how the answers there apply here.

2 Answers

The reason git fetch refuses to update your current branch is that git fetch is an operation that updates remote references only, not your local checked out copy.

You could insist and fetch over the current branch by adding the --update-head-ok switch, but the result is not good: the checked out files are not changed, only the HEAD, and git status reports changes reverting all those new commit. That's probably not what you want. (But a git reset --hard will fix things at this point, as @jthill pointed out in the comments, as long as you didn't have any unsaved work in your sandbox.)

Recommended method 1

As you said, checkout another branch before you do the fetch, and run

git checkout some-other-branch
git fetch myrepo.bundle HEAD:branchB
git checkout branchB

This way, an update is not related to the current state of your sandbox, so things work well.

If your repo has no other branches, you can just checkout any commit in detached-head mode instead of some-other-branch (e.g. from @jthill in the comments: git checkout @^0 checks out the current commit).

Recommended method 2

Now, maybe the operation you really wanted was:

git pull myrepo.bundle HEAD:branchB

When you do this while on branchB, that operation will work in a reasonable way, updating both your branch and the files in your checked out sandbox, and giving you this accurate warning: "warning: fetch updated the current branch head."

Method 3: roundabout but more verbose

A third method I sometimes use with bundles lets me inspect it with my preferred graphical git log tools before merging anything in. It is to add the bundle as another remote:

git remote add mybundle <path-to-bundle-file>
git fetch mybundle

Then, in the git logs, the branches in the bundle will show up at mybundle/<branch-name> and you can merge it in as if it came from a connected remote.

While more work, this method can be useful if you want to carefully analyze what the bundle provides before applying it.

At the factory default setting of merging your pulls, fast-forwarding if possible, git pull does the fetch-and-merge for you,

git pull your.bundle HEAD

or if you've got some pull configs set up you can be explicit with

git -c pull.ff=true -c pull.rebase=false pull your.bundle HEAD

either of which wind up doing the equivalent of

git fetch your.bundle HEAD
git merge FETCH_HEAD
Related