It's not clear to me how you created your local repository in the first place, but I suspect you did this:
mkdir new-repo
cd new-repo
git init
and then created some files and git add
ed them and committed the result. This would leave you with a new repository with just one commit in it, and no origin
remote, so you would then have had to run:
git remote add origin ssh://git@github.com/your/repo.git
or similar.
It's not clear to me how you created your/repo.git
(or whatever its path may be) on GitHub, but I suspect you used the "create a new repository with a README file in it" button.
If all of these "suspects" are correct, this explains everything. Your initial error:
fatal: 'origin/master' is not a commit and ...
occurred because you had not yet connected your Git to GitHub's Git that holds the repository you created at GitHub.
You then ran git fetch origin
, which had your Git connect to their Git and obtain their (single) commit containing a README file. Your Git copied their commit into your repository. Your Git then created your own origin/master
remote-tracking name, to remember the hash ID of their (single) commit.
You now have two initial (created-from-nothing) commits, which Git calls root commits. If we draw a diagram of your repository, it might look like this:
A <-- master
B <-- origin/master
Your first commit, represented here as A
—whatever its actual hash ID might be—holds the files you committed. Your branch name master
identifies this one commit.
Their first commit, represented here as B
, holds the files they committed. Your remote-tracking name origin/master
identifies this one commit.
You now ask your Git to create a new branch name master
pointing to commit B
, using your origin/master
, via the failing command:
git checkout --track origin/master
fatal: A branch named 'master' already exists.
The reason for the error message is clear: you already have a branch name master
, pointing to existing commit A
; it's not possible to create a new but identical branch name master
pointing to existing commit B
.
What to do about this
You have a number of options for proceeding from here. They mostly involve creating a new commit C
.
You can join your history (your one lone commit) to their history (their one lone commit) by using git merge
. To do so, you will need the --allow-unrelated-histories
option, unless your version of Git is old enough not to have the option. A Git that old just assumes that --allow-unrelated-histories
should always be implied.
If their lone commit B
is autogenerated, merging histories like this is a bit silly. It would make more sense to just throw out their commit entirely. Take anything you find useful from their commit B
and make your own new regular commit C
:
A <-C <-- master
B <-- origin/master
Your new commit C
will point only to your existing A
. You can now force them to throw away their commit B
, sending them your new C
.
Or, you can go ahead and merge the two commits:
A
\
C <-- master
/
B <-- origin/master
You can now send them commit C
and ask them to make their master
remember C
, which remembers both A
and B
.
To send them new commit C
(which will bring with it A
, and point back to A
, and maybe also to B
depending on how you made C
), use git push origin master
. This sends C
(and A
) and ends with a polite request that they please, if they would, make their name master
point to C
. If you deliberately threw out B
, by not making a merge, you'll need to upgrade the polite request to a command: git push --force origin master
.
When this is all done, their master
will also point to (their copy of the now-shared) commit C
. Your Git will update your own origin/master
to remember that their master
remembers C
, and you'll both agree that C
is the last commit of your and their branches, both of which are named master
.
Meanwhile, your own master
won't have origin/master
set as its upstream. There's no reason it must be, but if you'd like it to be—see Why do I need to do `--set-upstream` all the time?—you can use git branch --set-upstream-to
, or you can combine your git push
with the -u
option:
git push -u origin master
or:
git push --force -u origin master
(with the --force
option only required when you're telling them: *forget about your commit B
, it's useless, use my C
instead—which is not required if your C
points back to B
).
Instead of either merge or override, you have yet more options, which also create a new commit C
. You can:
- rebase your
A
on their B
, using git rebase -i --root
, or
- copy your
A
to a new commit C
that sits atop their B
, on a new branch not named master
.
The rebase works by doing the copy, then abandoning your original A
in favor of this new C
:
A [abandoned / lost - will eventually be garbage collected]
B <-- origin/master
\
C <-- master
Or:
A <-- master
B <-- origin/master
\
C <-- newbranch
You can then rename your master
, e.g., to old-master
and rename newbranch
to master
:
A <-- old-master
B <-- origin/master
\
C <-- master
In the end, you can now git push -u origin master
to send them commit C
(this time without sending A
at all) and ask them to set their master
to point to new commit C
.
How to make sense of all of this
Go back and re-examine all of the earlier diagrams and think about things like this:
- What matters to Git are the commits, which never change (but can be abandoned and eventually tossed entirely).
- Names, like
master
and origin/master
, merely serve to find the last commit in some sequence of commits.
- The hash ID of any commit—you'll see these big ugly hash IDs in
git log
output—is how Git finds a commit. By storing the last hash ID in each name, Git can find all the last ones. Each commit itself stores the big ugly hash ID of its immediate predecessor: commit C
points back to commit A
, or commit B
, or both, depending on how we make it.
It's the commits that actually matter. Git gives you the names, because names mean something to humans (who can't remember big ugly hash IDs), and then uses the names to find the commits. Those commits that Git can find by name, store hash IDs of earlier commits. Those earlier commits store hash IDs of even-earlier commits, and so on. The git log
command just starts at the current end and works backwards, showing you commits as it goes.