0

I created a new branch in my remote repository that was cloned off a feature branch using:

git clone <url> --branch <feature-branch-name> --single-branch <repo-name>

I now need to merge the latest changes from my dev branch, but I'm unable to clone it into my existing local repository and I'm unable to see it when I do git branch.

Any ideas on how I'll be able to do this?

I've tried regular cloning into the existing directory using the standard way and using the --branch dev --single-branch method, but no luck.

Bob Gilmore
  • 12,608
  • 13
  • 46
  • 53
Ricardo Francois
  • 752
  • 7
  • 24

2 Answers2

1

UPDATE, found this simple alternative

Create a new origin

git remote add *NewOriginName* *repositoryURL*

then create a new orphan branch

git checkout --orphan *myNewBranch*

this new branch will have no commits but all the files from the branch you started with, so you probably will want to delete all files on this new branch, then

git pull *NewOriginName* *branchOfInterestOnRepo* --allow-unrelated-histories

and thats it, you could need a new commit depending on the files you left on the new orphan branch


That sounds like a submodule

https://git-scm.com/book/en/v2/Git-Tools-Submodules

But if you dont want to keep the previous commits you can just download the files from the commit you need

If you prefer to use the console the way will be with

git clone -b <branchname> --single-branch <remote-repo-url>

This will not create a branch, this will get the files on your active branch, in a new directory, this directory with the name of the brach from the repository

0

You will want to un-single-branch-ize your repository. You have two obvious paths to go by here. One option is to undo the single branch aspect: see How do I "undo" a --single-branch clone? (for which this would be a duplicate of that question). The other requires that you read the git remote documentation, paying particular attention to the set-branches sub-command with its --add sub-option.

Once you've done this, run git fetch, then git checkout branch-name or git switch branch-name. Git will create the new branch. Or, use the remote-tracking name origin/branch-name. See below for more about remote-tracking names.

Background (optional reading, but a good idea)

It's important to realize that your base assumption here is subtly wrong though:

my remote repository ... was cloned off a feature branch [and] I'm unable to clone [dev] into my existing local repository

The bad assumption embedded here is that git clone command doesn't clone a branch. Git's git clone command is a sort of convenience command, shorthand for running six other commands. Five of those six other commands are Git commands. For illustration, here are the six commands, in the order they are run:

  1. mkdir (or your OS's equivalent): creates a new, empty directory or folder (whichever term you prefer). The remaining commands are run in this new directory, although once git clone finishes, you also have to move into this new folder yourself. (There's one mode where this command gets skipped, when you tell git clone about an existing, empty directory that it should use.)

  2. git init: this creates a new, empty repository, with no commits. A repository that has no commits cannot have any branches, so it also has no branches.

  3. git remote add origin url: this adds what Git calls a remote to the empty repository. A remote is simply a short name—here, origin—that will hold a few things. The main thing it holds is a URL, but it also holds instructions for future git fetch commands.

    The git remote add sub-command can take a -t option to specify a particular branch name of interest. The --single-branch option to git clone adds this -t option. (The git remote add sub-command can also use a name other than origin. Using -o in git clone does this, but we'll assume that you did not use -o and hence use the name origin.)

  4. Any other git config commands implied by -c options to git clone. (These -c options must be at the right place in the command-line arguments: some -c options are handled by the git front end rather than the clone command.) If you did not use such options, git clone does nothing during this step as there is nothing to do.

  5. git fetch origin (or other name supplied via -o): this obtains commits from the other Git, the one that responds to the URL you supplied. This does not create any branch names in your repository. Your new repository still has no branches in it at this point.

  6. git checkout: this creates one branch in your new repository. The branch it creates is the one you supplied with the -b option. If you did not supply a -b option, it creates the branch whose name is recommended by the other Git.

    If you use the -n or --no-checkout option, git clone skips this step.

So whether or not you use --single-branch, step 6 of git clone creates only one branch. You only have one branch in this new repository! A normal clone copies all commits from the source repository, and none of the branches, and then Git creates one branch as a last step.

What --single-branch does is just one thing, but has several effects. That's because of the way git fetch works. At step 5, when git fetch runs, the fetch command connects to the other Git and its repository. The other Git lists out all of its branch names and other names.1 Your Git can choose to heed all of these names, or just a few of them (e.g., just one branch name). Each of these names also lists a raw commit hash ID, and it's these hash IDs—not the names!—that Git needs. They are how Git finds commits, and other important objects, and they are how your repository clones the other repository.

In any case, having obtained the appropriate commits and other objects, your Git now takes their Git's branch names—the ones they listed to let your Git find commits—and changes them. Your Git stores them—or some selected subset of them, such as exactly one of them—in your own repository as remote-tracking names.

The --single-branch option tells your Git to leave instructions for fetch to create or update only the one remote-tracking name corresponding to the one branch name in their Git. The default, of course, is to create or update a remote-tracking name for every branch that the other Git lists out, every time. If you use git remote to add more of their branch names, each git fetch will create or update each of those names, provided that the other Git is listing them on each fetch. So by undoing the single-branch-ness, or adding more names, you can get your own Git to create more remote-tracking names.


1The data here can be painfully large—on the order of megabytes—in some repositories with tens of thousands of branch and tag names, and hence there's a way to limit it in the latest Git communication protocols. Older Gits always get everything and the default, for a non-single-branch Git, is to get everything, so that it all still works right, but this does mean that if both your machine and your server have a newer Git version, the single-branch modes can be quite useful in some special cases today.


Branch names and remote-tracking names

A branch name is a name you make up yourself, that should have some meaning to you. This simply stores the hash ID of one (1) commit. By definition, this one commit is the latest commit on the branch. This allows Git to find that commit, and commits in Git allow Git to find more commits in Git. By finding the last one, Git can find all of the commits that go with that branch.

(This means that the word branch is ambiguous: does it refer to the name, such as dev or main or whatever? Or does it refer to the collection of commits ended by the latest one? The answer is one, both, or neither, depending on who says it and what they meant when they said it. See also What exactly do we mean by "branch"?)

A remote-tracking name is made up of the name of the remote—origin—plus a slash, followed by the original branch name.2 These names, like branch names, allow Git to find commits. But they're not actually branch names. You can tell the difference because:

git checkout somebranch

tells you that you are now "on" the branch, and git branch and git status tell you that you are now on branch somebranch (using that exact phrase for git status). But:

git checkout origin/somebranch

tells you that you are now in what Git calls detached HEAD mode, and git branch and git status show that you are no longer on any branch. (This mode is fine for looking at commits, but not a good idea to stay in to do new work. To exit this mode, run git checkout with the name of one of your branches, as shown by git branch's output.)

When you ask Git to switch to a branch named B, Git checks first to see if you have a branch named B. If you do, Git switches to it.3 But if not, just before saying "I can't switch to that because it doesn't exist", the checkout or switch command (whichever one you used) will see if there's some obvious origin/B that could be used to create B. If so, the Git command will create B using origin/B,4 then switch to it. This is in fact how step 6 of git clone works.


2Technically, these remote-tracking names are in a separate namespace. The full spelling of a remote-tracking name begins with refs/remotes/ while the full spelling of a branch name begins with refs/heads/. Git usually strips off the refs/remotes/ and refs/heads/ parts. Oddly, under git branch -a, the remote-tracking names are listed with only refs/ stripped off.

3This assumes that said switching is possible. It is possible if you're in a "clean" state, i.e., have not modified anything. It is sometimes possible even if not. See also Checkout another branch when there are uncommitted changes on the current branch

4In fact, any remote-tracking name, even if it starts with something other than origin/, works here. The "using" part means that your new branch is created using the same commit hash ID stored in your own repository's remote-tracking name.

torek
  • 448,244
  • 59
  • 642
  • 775