1

I saw a git command from unable to create file ... Permission denied

git checkout origin develop

I only know check out a local branch. What does it mean to have a remote repository and a remote branch as arguments to checkout? I can't find it in https://git-scm.com/docs/git-checkout

  • I think you are able to checkout a branch to your local repository that tracks a remote branch. https://git-scm.com/book/en/v1/Git-Branching-Remote-Branches – Jerinaw Jan 20 '19 at 17:43

3 Answers3

2

The command git checkout origin develop means "check out file (file, not branch!) named develop from the branch (branch, not remote!) named origin". If you have branch origin and the branch points to a commit containing file develop the command succeeds.

But you probably have neither one so the command actually doesn't make sense. StackOverflow is full of bad questions and incorrect answers; don't believe everything you see.

A meaningful command here could be git checkout origin/develop which means "check out commit pointed to by the remote tracking reference named origin/develop".

Another meaningful command here could be git checkout develop which means "create a new local branch named develop branching it from the remote tracking reference named origin/develop; setup tracking so that the remote tracking reference named origin/develop becomes the upstream branch for the local branch named develop".

See the git checkout docs at https://git-scm.com/docs/git-checkout

phd
  • 82,685
  • 13
  • 120
  • 165
2

TL;DR

You don't have both a repository and a branch here. Instead, you have a tree-ish and a pathspec. The tree-ish is a commit specifier, origin, which is short for origin/HEAD, which is short for ... well, see below. The pathspec is develop which just means the file named develop. If there is no such file, this command will simply fail.

Long: how to read Git documentation

The syntax for git checkout is:

  1. git checkout [-q] [-f] [-m] [<branch>]
  2. git checkout [-q] [-f] [-m] --detach [<branch>]
  3. git checkout [-q] [-f] [-m] [--detach] <commit>
  4. git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
  5. git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
  6. git checkout [<tree-ish>] [--] <pathspec>...
  7. git checkout (-p|--patch) [<tree-ish>] [--] [<paths>...]

None of these allow you to specify a branch name twice.

Try matching:

git checkout origin develop

to the above seven possible syntax lines. It doesn't match #1, which allows only one <branch> argument and no additional arguments. It doesn't match #2, which requires a literal --detach. It doesn't match #3, which allows only one <commit> argument and no daditional arguments. It doesn't match #4, which allows only one optional <start-point> argument, and it doesn't match #7, which requires a literal -p or --patch.

It does match #5 and #6. These probably shouldn't be two separate syntax lines, and in the subsequent description section, they aren't—it's just one section with:

git checkout [<tree-ish>] -- [<pathspec> ...]

which has the flaw that it fails to mention all the optional flags in the shortened summary, but it then mentions those flags in the body of the text:

Overwrite paths in the working tree by replacing with the contents in the index or in the <tree-ish> (most often a commit). When a <tree-ish> is given, the paths that match the <pathspec> are updated both in the index and in the working tree.

The index may contain unmerged entries because of a previous failed merge. By default ... [snip - this is where flags like -f and --ours and so on get mentioned]

Now, this text is full of Git jargon, in particular tree-ish and pathspec. (Side note: tree-ish is defined in the Gitglossary, but I'm going to use a more pointed defintion here.)

The term tree-ish means: I, Git, am fine here if you name a specific commit. All I'm going to do with the commit is find its internal tree object, so you can give me that directly, if for some odd reason you really want to. But really, just gimme something I can translate to a commit or tree, and I'll use the tree, or use the commit to find the tree.

You provided origin here, and now it's time to go look at another piece of Git documentation. (What, another one? Already?) The gitrevisions documentation describes a six-step process for turning a name, like master or develop or v2.1, into a Git object hash ID.

The first step is to check whether there is a file in .git that has that name, and that step lets you use a name like CHERRY_PICK_HEAD while you're in the middle of a conflicted git cherry-pick. In this case, it doesn't apply.

The second step is to try the name as refs/name. That second step lets you use stash or stash@{number} when you are using git stash. In this case, it doesn't apply either.

The third step is to try the name as refs/tags/name. That third step lets you use a name like v2.1 to refer to the tag v2.1. Since origin probably is not a valid tag name—you didn't tag any of your commits origin, did you?—this step is going to fail, so Git will move on to step #4.

The fourth step is to try the name as refs/heads/name. This step allows you to use a branch name to specify a commit. That's what lets you git checkout master -- somefile, for instance. Since master is a valid branch name, git checkout will find the specific commit that master names—the tip of the master branch—and use that commit's tree—remember, we're executing the git checkout <tree-ish> [--] <pathspec>... syntax, and working on the <tree-ish> part here.

But you don't have a branch named origin, do you? You might, if you created one! I'd advise against creating one, but if you did, that's where this six-step process will stop. Assuming you don't, though, the process goes on to step five.

Step five tries the name as refs/remotes/name. You will have a directory named refs/remotes/origin/ but that's not a valid ref so step five will fail, and the process will move to the last step. If the last step fails, the whole thing fails, but...

Step six, the final one, tries the name as refs/remotes/name/HEAD. Since origin is a valid remote, this will exist (well, unless you specifically deleted it, or in one other case that's not going to occur), and will be a valid commit specifier. So step six succeeds: it finds that refs/remotes/origin/HEAD exists and (probably) names refs/remotes/origin/master, which also exists, and that names a commit.

Thus, at this point the <tree-ish> part of the whole process is satisified: Git has translated origin to refs/remotes/origin/HEAD, or origin/HEAD for short; that's (probably) the same as refs/remotes/origin/master, or origin/master for short; and that's a valid commit, which would serve for either git checkout syntax rule #3 or for git checkout syntax rules #5 & #6.

Since we're working on the #5/#6 rules, we can go on and treat the last argument, develop, as a <pathspec>. Now we have to look at yet another piece of Git documentation, namely the Gitglossary. We can jump straight to the definition of a pathspec, which is, unfortunately, very long and I'm not going to go through all of it here.

To sum up, though, a pathspec can be, and in this case is, just a file name. So develop becomes a file name, and we have finished all the requirements for syntax rule(s) #5/#6. Git will execute the action described in the yellow quoted text above, replacing the file develop in the index and work-tree, or simply erroring-out if the file develop does not exist by that name in the commit/<tree-ish> that we chose with the name origin.

torek
  • 448,244
  • 59
  • 642
  • 775
  • By the way, `git checkout [--] ...` will be chattier with Git 2.21: https://stackoverflow.com/a/54281959/6309 – VonC Jan 21 '19 at 05:53
1

The command git checkout origin develop does not make much sense, because in Git only local branches are checked out. Using origin develop refers to the develop branch on the remote. You probably meant to do this:

git checkout develop

Assuming that there exists a remote tracking branch origin/develop (which is actually a local branch), the above would tell Git to create a new local branch called develop, which tracks the remote branch via the tracking branch origin/develop.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360