Related
I accidentally ran git merge some_other_branch on my local master branch. I haven't pushed the changes to origin master. How do I undo the merge?
After merging, git status says:
# On branch master
# Your branch is ahead of 'origin/master' by 5 commits.
How do I undo all these commits?
With git reflog check which commit is one prior the merge (git reflog will be a better option than git log). Then you can reset it using:
git reset --hard commit_sha
There's also another way:
git reset --hard HEAD~1
It will get you back 1 commit.
Be aware that any modified and uncommitted/unstashed files will be reset to their unmodified state. To keep them either stash changes away or see --merge option below.
As #Velmont suggested below in his answer, in this direct case using:
git reset --hard ORIG_HEAD
might yield better results, as it should preserve your changes. ORIG_HEAD will point to a commit directly before merge has occurred, so you don't have to hunt for it yourself.
A further tip is to use the --merge switch instead of --hard since it doesn't reset files unnecessarily:
git reset --merge ORIG_HEAD
--merge
Resets the index and updates the files in the working tree that are different between <commit> and HEAD, but keeps those which are different between the index and working tree (i.e. which have changes which have not been added).
Assuming your local master was not ahead of origin/master, you should be able to do
git reset --hard origin/<branch-name>
So assuming you did this on master, then your local master branch should look identical to origin/master.
See chapter 4 in the Git book and the original post by Linus Torvalds.
To undo a merge that was already pushed:
git revert -m 1 commit_hash
Be sure to revert the revert if you're committing the branch again, like Linus said.
It is strange that the simplest command was missing. Most answers work, but undoing the merge you just did, this is the easy and safe way:
git reset --merge ORIG_HEAD
The ref ORIG_HEAD will point to the original commit from before the merge.
(The --merge option has nothing to do with the merge. It's just like git reset --hard ORIG_HEAD, but safer since it doesn't touch uncommitted changes.)
With newer Git versions, if you have not committed the merge yet and you have a merge conflict, you can simply do:
git merge --abort
From man git merge:
[This] can only be run after the merge has resulted in conflicts. git merge --abort will abort the merge process and try to reconstruct the pre-merge state.
You should reset to the previous commit. This should work:
git reset --hard HEAD^
Or even HEAD^^ to revert that revert commit. You can always give a full SHA reference if you're not sure how many steps back you should take.
In case when you have problems and your master branch didn't have any local changes, you can reset to origin/master.
Lately, I've been using git reflog to help with this. This mostly only works if the merge JUST happened, and it was on your machine.
git reflog might return something like:
fbb0c0f HEAD#{0}: commit (merge): Merge branch 'master' into my-branch
43b6032 HEAD#{1}: checkout: moving from master to my-branch
e3753a7 HEAD#{2}: rebase finished: returning to refs/heads/master
e3753a7 HEAD#{3}: pull --rebase: checkout e3753a71d92b032034dcb299d2df2edc09b5830e
b41ea52 HEAD#{4}: reset: moving to HEAD^
8400a0f HEAD#{5}: rebase: aborting
The first line indicates that a merge occurred. The 2nd line is the time before my merge. I simply git reset --hard 43b6032 to force this branch to track from before the merge, and carry-on.
If you are in a middle of merging you can always abort it
git merge --abort
With modern Git, you can:
git merge --abort
Older syntax:
git reset --merge
Old-school:
git reset --hard
But actually, it is worth noticing that git merge --abort is only equivalent to git reset --merge given that MERGE_HEAD is present. This can be read in the Git help for merge command.
git merge --abort is equivalent to git reset --merge when MERGE_HEAD is present.
After a failed merge, when there is no MERGE_HEAD, the failed merge can be undone with git reset --merge, but not necessarily with git merge --abort, so they are not only old and new syntax for the same thing.
Personally I find git reset --merge much more powerful and useful in everyday work, so that's the one I always use.
If branches are merged and not pushed, then git reset command given below will work to undo the merge:
git reset --merge ORIG_HEAD
Example:
git reset --merge origin/master
Okay, the answers other people here gave me were close, but it didn't work. Here's what I did.
Doing this...
git reset --hard HEAD^
git status
...gave me the following status.
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 3 and 3 different commit(s) each, respectively.
I then had to type in the same git reset command several more times. Each time I did that, the message changed by one as you can see below.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 3 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 2 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 1 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch is behind 'origin/master' by 3 commits, and can be fast-forwarded.
At this point, I saw the status message changed, so I tried doing a git pull, and that seemed to work:
> git pull
Updating 2df6af4..12bbd2f
Fast forward
app/views/truncated | 9 ++++++---
app/views/truncated | 13 +++++++++++++
app/views/truncated | 2 +-
3 files changed, 20 insertions(+), 4 deletions(-)
> git status
# On branch master
So long story short, my commands came down to this:
git reset --hard HEAD^
git reset --hard HEAD^
git reset --hard HEAD^
git reset --hard HEAD^
git pull
You have to change your HEAD, Not yours of course but git HEAD....
So before answering let's add some background, explaining what is this HEAD.
First of all what is HEAD?
HEAD is simply a reference to the current commit (latest) on the current branch.
There can only be a single HEAD at any given time. (excluding git worktree)
The content of HEAD is stored inside .git/HEAD and it contains the 40 bytes SHA-1 of the current commit.
detached HEAD
If you are not on the latest commit - meaning that HEAD is pointing to a prior commit in history its called detached HEAD.
On the command line, it will look like this- SHA-1 instead of the branch name since the HEAD is not pointing to the tip of the current branch
A few options on how to recover from a detached HEAD:
git checkout
git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back
This will checkout new branch pointing to the desired commit.
This command will checkout to a given commit.
At this point, you can create a branch and start to work from this point on.
# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>
# create a new branch forked to the given commit
git checkout -b <branch name>
git reflog
You can always use the reflog as well.
git reflog will display any change which updated the HEAD and checking out the desired reflog entry will set the HEAD back to this commit.
Every time the HEAD is modified there will be a new entry in the reflog
git reflog
git checkout HEAD#{...}
This will get you back to your desired commit
git reset --hard <commit_id>
"Move" your HEAD back to the desired commit.
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
Note: (Since Git 2.7)
you can also use the git rebase --no-autostash as well.
git revert <sha-1>
"Undo" the given commit or commit range.
The reset command will "undo" any changes made in the given commit.
A new commit with the undo patch will be committed while the original commit will remain in the history as well.
# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>
This schema illustrates which command does what.
As you can see there reset && checkout modify the HEAD.
It can be done multiple ways.
1) Abort Merge
If you are in-between a bad merge (mistakenly done with wrong branch), and wanted to avoid the merge to go back to the branch latest as below:
git merge --abort
2) Reset HEAD to remote branch
If you are working from remote develop branch, you can reset HEAD to the last commit on remote branch as below:
git reset --hard origin/develop
3) Delete current branch, and checkout again from the remote repository
Considering, you are working on develop branch in local repo, that syncs with remote/develop branch, you can do as below:
git checkout master
##to delete one branch, you need to be on another branch, otherwise you will fall with the branch :)
git branch -D develop
git checkout -b develop origin/develop
You could use git reflog to find the previous checkout. Sometimes that's a good state you want to return back to.
Concretely,
$ git reflog
$ git reset --hard HEAD#{0}
I was able to resolve this problem with a single command that doesn't involve looking up a commit id.
git reset --hard remotes/origin/HEAD
The accepted answer didn't work for me but this command achieved the results I was looking for.
If you didn't commit it yet, you can only use
$ git checkout -f
It will undo the merge (and everything that you did).
Got to this question also looking to revert to match origin (ie, NO commits ahead of origin). Researching further, found there's a reset command for exactly that:
git reset --hard #{u}
Note: #{u} is shorthand for origin/master. (And, of course, you need that remote repository for this to work.)
if no conflict and merge completed then:
git reset --hard HEAD~1
if while doing a merge got conflict then abort will take you out of the recent merge changes:
git merge --abort
or if you want to revert back to a specific commit id.
git reset --hard <commit-id>
Answering the question "Undo a Git merge that hasn't been pushed yet"
You can use git reset --hard HEAD~1
Consider the following situation where there are 2 branches master and feature-1:
$ git log --graph --oneline --all
Do Git merge
$ git merge feature-1
$ git log --graph --oneline --all
Undo Git merge
$ git reset --hard HEAD~1
$ git log --graph --oneline --all
You can use only two commands to revert a merge or restart by a specific commit:
git reset --hard commitHash (you should use the commit that you want to restart, eg. 44a587491e32eafa1638aca7738)
git push origin HEAD --force (Sending the new local master branch to origin/master)
Good luck and go ahead!
The simplest answer is the one given by odinho - Velmont
First do git reset --merge ORIG_HEAD
For those looking to reset after changes are pushed, do this
(Because this is the first post seen for any git reset merge questions)
git push origin HEAD --force
This will reset in a way that you won't get the merged changes back again after pull.
Just for an extra option to look at, I've been mostly following the branching model described here: http://nvie.com/posts/a-successful-git-branching-model/ and as such have been merging with --no-ff (no fast forward) usually.
I just read this page as I'd accidentally merged a testing branch instead of my release branch with master for deploying (website, master is what is live). The testing branch has two other branches merged to it and totals about six commits.
So to revert the whole commit I just needed one git reset --hard HEAD^ and it reverted the whole merge. Since the merges weren't fast forwarded the merge was a block and one step back is "branch not merged".
If your merge and the corresponding commits were not pushed yet, you can always switch to another branch, delete the original one and re-create it.
For example, I accidentally merged a develop branch into master and wanted to undo that. Using the following steps:
git checkout develop
git branch -D master
git branch -t master origin/master
Voila! Master is at the same stage as origin, and your mis-merged state is erased.
Strategy: Create a new branch from where everything was good.
Rationale: Reverting a merge is hard. There are too many solutions, depending on many factors such as whether you've committed or pushed your merge or if there were new commits since your merge. Also you still need to have a relatively deep understanding of git to adapt these solutions to your case. If you blindly follow some instructions, you can end up with an "empty merge" where nothing will be merged, and further merge attempts will make Git tell you "Already up to date".
Solution:
Let's say you want to merge dev into feature-1.
Find the revision that you want to receive the merge:
git log --oneline feature-1
a1b2c3d4 Merge branch 'dev' into 'feature-1' <-- the merge you want to undo
e5f6g7h8 Fix NPE in the Zero Point Module <-- the one before the merge, you probably want this one
Check it out (go back in time):
git checkout e5f6g7h8
Create a new branch from there and check it out:
git checkout -b feature-1
Now you can restart your merge:
Merge: git merge dev
Fix your merge conflicts.
Commit: git commit
When you're satisfied with the results, delete the old branch: git branch --delete feature-1
If you want a command-line solution, I suggest to just go with MBO's answer.
If you're a newbie, you might like the graphical approach:
Kick off gitk (from the command line, or right click in file browser if you have that)
You can easily spot the merge commit there - the first node from the top with two parents
Follow the link to the first/left parent (the one on your current branch before the merge, usually red for me)
On the selected commit, right-click "Reset branch to here", pick the hard reset there
Just create new branch, then cherry-pick desired commits to it.
Its saver and simpler then resets described in many answers above
I think you can do git rebase -i [hash] [branch_name] where [hash] is the identifying hash for however far back you want to rewind plus one (or however many commits back you want to go) and then delete the lines for the commits in the editor that you don't want any more. Save the file. Exit. Pray. And it should be rewound. You might have to do a git reset --hard, but it should be good at this point. You can also use this to pull specific commits out of a stack, if you don't want to keep them in your history, but that can leave your repository in a state that you probably don't want.
Use this command to abort a merge:
git merge --abort
First, make sure that you've committed everything.
Then reset your repository to the previous working state:
$ git reset f836e4c1fa51524658b9f026eb5efa24afaf3a36
or using --hard (this will remove all local, not committed changes!):
$ git reset f836e4c1fa51524658b9f026eb5efa24afaf3a36 --hard
Use the hash which was there before your wrongly merged commit.
Check which commits you'd like to re-commit on the top of the previous correct version by:
$ git log 4c3e23f529b581c3cbe95350e84e66e3cb05704f
commit 4c3e23f529b581c3cbe95350e84e66e3cb05704f
...
commit 16b373a96b0a353f7454b141f7aa6f548c979d0a
...
Apply your right commits on the top of the right version of your repository by:
By using cherry-pick (the changes introduced by some existing commits)
git cherry-pick ec59ab844cf504e462f011c8cc7e5667ebb2e9c7
Or by cherry-picking the range of commits by:
First checking the right changes before merging them:
git diff 5216b24822ea1c48069f648449997879bb49c070..4c3e23f529b581c3cbe95350e84e66e3cb05704f
First checking the right changes before merging them:
git cherry-pick 5216b24822ea1c48069f648449997879bb49c070..4c3e23f529b581c3cbe95350e84e66e3cb05704f
where this is the range of the correct commits which you've committed (excluding wrongly committed merge).
The simplest of the simplest chance, much simpler than anything said here:
Remove your local branch (local, not remote) and pull it again. This way you'll undo the changes on your master branch and anyone will be affected by the change you don't want to push. Start it over.
Yesterday, I posted a question on how to clone a Git repository from one of my machines to another, How can I 'git clone' from another machine?.
I am now able to successfully clone a Git repository from my source (192.168.1.2) to my destination (192.168.1.1).
But when I did an edit to a file, a git commit -a -m "test" and a git push, I get this error on my destination (192.168.1.1):
git push
hap#192.168.1.2's password:
Counting objects: 21, done.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 1010 bytes, done.
Total 11 (delta 9), reused 0 (delta 0)
error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.
error:
error: You can set 'receive.denyCurrentBranch' configuration variable to
error: 'ignore' or 'warn' in the remote repository to allow pushing into
error: its current branch; however, this is not recommended unless you
error: arranged to update its work tree to match what you pushed in some
error: other way.
error:
error: To squelch this message and still keep the default behaviour, set
error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To git+ssh://hap#192.168.1.2/media/LINUXDATA/working
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'git+ssh://hap#192.168.1.2/media/LINUXDATA/working'
I'm using two different versions of Git (1.7 on the remote and 1.5 on the local machine). Is that a possible reason?
The error message error: refusing to update checked out branch: refs/heads/master is emitted by the remote repository and it means you're trying to push code to remote non-bare repository that has different code currently checked out in the working directory. The best way to avoid this problem is to push to bare repositories only - this problem cannot ever happen with a bare repository.
You can simply convert your remote repository to bare repository (there is no working copy in the bare repository - the folder contains only the actual repository data).
Execute the following command in your remote repository folder:
git config --bool core.bare true
Then delete all the files except .git in that folder. And then you will be able to perform git push to the remote repository without any errors.
I just had the same error while I began learning Git. Some of the other answers are clearly not for someone new to Git!
I am going to use non technical terms to get the idea across. Anyway, what is happening is that you have two repositories, one is the original you first made, and the other the work one you just made.
Right now you are in your work repository and are using the master branch. But you also happen to be "logged in" in your original repository to the same master branch. Now since you're "logged in" in the original, Git fears you might mess up because you might be working on the original and screw things up. So you need to return to the original repository and do git checkout someotherbranch, and now you can push with no problems.
The error message describes what has happened. More modern versions of Git refuse to update a branch via a push if that branch is checked out.
The easiest way to work between two non-bare repositories is either to
always update the repositories by pull (or fetch and merge) or, if you have to,
by pushing to a separate branch (an import branch) and then merging that branch into the master branch on the remote machine.
The reason for this restriction is that the push operation operates only on the remote Git repository, it doesn't have access to the index and working tree. So, if allowed, a push on the checked-out branch would change the HEAD to be inconsistent with the index and working tree on the remote repository.
This would make it very easy to accidentally commit a change that undoes all of the pushed changes and also makes it very difficult to distinguish between any local changes that have not been committed and differences between the new HEAD, the index and the working tree that have been caused by push moving HEAD.
Summary
You cannot push to the one checked out branch of a repository because it would mess with the user of that repository in a way that will most probably end with loss of data and history. But you can push to any other branch of the same repository.
As bare repositories never have any branch checked out, you can always push to any branch of a bare repository.
There are multiple solutions, depending on your needs.
Solution 1: Use a Bare Repostiory
As suggested, if on one machine, you don't need the working directory, you can move to a bare repository. To avoid messing with the repository, you can just clone it:
machine1$ cd ..
machine1$ mv repo repo.old
machine1$ git clone --bare repo.old repo
Now you can push all you want to the same address as before.
Solution 2: Push to a Non-Checked-Out Branch
But if you need to check out the code on your remote <remote>, then you can use a special branch to push. Let's say that in your local repository you have called your remote origin and you're on branch master. Then you could do
machine2$ git push origin master:master+machine2
Then you need to merge it when you're in the origin remote repo:
machine1$ git merge master+machine2
Autopsy of the Problem
When a branch is checked out, committing will add a new commit with the current branch's head as its parent and move the branch's head to be that new commit.
So
A ← B
↑
[HEAD,branch1]
becomes
A ← B ← C
↑
[HEAD,branch1]
But if someone could push to that branch inbetween, the user would get itself in what git calls detached head mode:
A ← B ← X
↑ ↑
[HEAD] [branch1]
Now the user is not in branch1 anymore, without having explicitly asked to check out another branch. Worse, the user is now outside any branch, and any new commit will just be dangling:
[HEAD]
↓
C
↙
A ← B ← X
↑
[branch1]
Hypothetically, if at this point, the user checks out another branch, then this dangling commit becomes fair game for Git's garbage collector.
You can get around this "limitation" by editing the .git/config on the destination server. Add the following to allow a git repository to be pushed to even if it is "checked out":
[receive]
denyCurrentBranch = warn
or
[receive]
denyCurrentBranch = false
The first will allow the push while warning of the possibility to mess up the branch, whereas the second will just quietly allow it.
This can be used to "deploy" code to a server which is not meant for editing. This is not the best approach, but a quick one for deploying code.
git config --local receive.denyCurrentBranch updateInstead
https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155
Use that on the server repository, and it also updates the working tree if no untracked overwrite would happen.
It was added in Git 2.3 as mentioned by VonC in the comments.
I've compiled Git 2.3 and gave it a try. Sample usage:
git init server
cd server
touch a
git add .
git commit -m 0
git config --local receive.denyCurrentBranch updateInstead
cd ..
git clone server local
cd local
touch b
git add .
git commit -m 1
git push origin master:master
cd ../server
ls
Output:
a
b
Yay, b got pushed!
I like the idea of still having a usable repository on the remote box, but instead of a dummy branch, I like to use:
git checkout --detach
This seems to be a very new feature of Git - I'm using git version 1.7.7.4.
I had the same issue. For me, I use Git push to move code to my servers. I never change the code on the server side, so this is safe.
In the repository, you are pushing to type:
git config receive.denyCurrentBranch ignore
This will allow you to change the repository while it's a working copy.
After you run a Git push, go to the remote machine and type this:
git checkout -f
This will make the changes you pushed be reflected in the working copy of the remote machine.
Please note, this isn't always safe if you make changes on in the working copy that you're pushing to.
You can recreate your server repository and push from your local branch master to the server master.
On your remote server:
mkdir myrepo.git
cd myrepo.git
git init --bare
OK, from your local branch:
git push origin master:master
What you probably did to cause this:
This kind of thing happens when you go to bang out a little program. You're about to change something which was already working, so you cast your level-3 spell of perpetual undoability:
machine1:~/proj1> git init
and you start adding/committing. But then, the project starts getting more involved and you want to work on it from another computer (like your home PC or laptop), so you do something like
machine2:~> git clone ssh://machine1/~/proj1
and it clones and everything looks good, and so you work on your code from machine2.
Then... you try to push your commits from machine2, and you get the warning message in the title.
The reason for this message is because the git repo you pulled from was kinda intended to be used just for that folder on machine1. You can clone from it just fine, but pushing can cause problems. The "proper" way to be managing the code in two different locations is with a "bare" repo, like has been suggested. A bare repo isn't designed to have any work being done in it, it is meant to coordinate the commits from multiple sources. This is why the top-rated answer suggests deleting all files/folders other than the .git folder after you git config --bool core.bare true.
Clarifying the top-rated answer: Many of the comments to that answer say something like "I didn't delete the non-.git files from the machine1 and I was still able to commit from machine2". That's right. However, those other files are completely "divorced" from the git repo, now. Go try git status in there and you should see something like "fatal: This operation must be run in a work tree". So, the suggestion to delete the files isn't so that the commit from machine2 will work; it's so that you don't get confused and think that git is still tracking those files. But, deleting the files is a problem if you still want to work on the files on machine1, isn't it?
So, what should you really do?
Depends upon how much you plan to still work on machine1 and machine2...
If you're done developing from machine1 and have moved all of your development to machine2... just do what the top-rated answer suggests: git config --bool core.bare true and then, optionally, delete all files/folders other than .git from that folder, since they're untracked and likely to cause confusion.
If your work on machine2 was just a one-time thing, and you don't need to continue development there... then don't bother with making a bare repo; just ftp/rsync/scp/etc. your files from machine*2* on top of the files on machine*1*, commit/push from machine*1*, and then delete the files off of machine*2*. Others have suggested creating a branch, but I think that's a little messy if you just want to merge some development you did on a one-time basis from another machine.
If you need to continue development on both machine1 and machine2... then you need to set things up properly. You need to convert your repo to a bare, then you need to make a clone of that on machine1 for you to work in. Probably the quickest way to do this is to do
machine1:~/proj1> git config --bool core.bare true
machine1:~/proj1> mv .git/ ../proj1.git
machine1:~/proj1> cd ..
machine1:~> rm -rf proj1
machine1:~> git clone proj1.git
machine1:~> cd proj1
Very important: because you've moved the location of the repo from proj1 to proj1.git, you need to update this in the .git/config file on machine2. After that, you can commit your changes from machine2. Lastly, I try to keep my bare repos in a central location, away from my work trees (i.e. don't put 'proj1.git' in the same parent folder as 'proj1'). I advise you to do likewise, but I wanted to keep the steps above as simple as possible.
With a few setup steps you can easily deploy changes to your website using a one-liner like
git push production
Which is nice and simple, and you don't have to log into the remote server and do a pull or anything. Note that this will work best if you don't use your production checkout as a working branch! (The OP was working within a slightly different context, and I think #Robert Gould's solution addressed it well. This solution is more appropriate for deployment to a remote server.)
First you need to set up a bare repository somewhere on your server, outside of your webroot.
mkdir mywebsite.git
cd mywebsite.git
git init --bare
Then create file hooks/post-receive:
#!/bin/sh
GIT_WORK_TREE=/path/to/webroot/of/mywebsite git checkout -f
And make the file executable:
chmod +x hooks/post-receive
On your local machine,
git remote add production git#myserver.com:mywebsite.git
git push production +master:refs/heads/master
All set! Now in the future you can use git push production to deploy your changes!
Credit for this solution goes to http://sebduggan.com/blog/deploy-your-website-changes-using-git/. Look there for a more detailed explanation of what's going on.
You should only be pushing to a bare repository. A bare repository is a repository that has no checked out branches. If you were to cd to a bare repository directory, you'd only see the contents of a .git directory.
Check your .git/config in the destination project:
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[receive]
denyCurrentBranch = updateInstead
If the core. bare is false, you can set it to true:
$ git config core.bare true
and then in your local push to remote:
git push remote_repo // suppose the destination repo is remote_repo
it will success, in the remote_repo you can check git version.
$ git log -1
commit 0623b1b900ef7331b9184722a5381bbdd2d935ba
Author: aircraft < aircraft_xxx#126.com>
Date: Thu May 17 21:54:37 2018 +0800
and now you can not use git in your "workspace":
$ git status
fatal: This operation must be run in a work tree
you should set bare.bare back to false.
$ git config core.bare false
You have 3 options
Pull and push again:
git pull; git push
Push into different branch:
git push origin master:foo
and merge it on remote (either by git or pull-request)
git merge foo
Force it (not recommended unless you deliberately changed commits via rebase):
git push origin master -f
If still refused, disable denyCurrentBranch on remote repository:
git config receive.denyCurrentBranch ignore
In fact, set the remote to a non-checked out branch is sufficient. After you checked out your remote in a different branch, you can push.
I had the same problem using Git to synchronise repositories on my Android phone and laptop. The solution for me was to do a pull instead of a push, as #CharlesBailey suggested.
git push origin master on the Android repository fails for me with the same error messages that #hap497 got because of a push to a nonbare checkout of a repository + working-copy.
git pull droid master on the laptop repository and working-copy works for me. Of course, you need to have previously run something like git remote add droid /media/KINGSTON4GB/notes_repo/.
Older versions of Git used to allow pushes to the currently checked out branch of a non-bare repository.
It turns out this was a terribly confusing thing to allow. So they added the warning message you see, which is also terribly confusing.
If the first repository is just acting as a server then convert it to a bare repository as the other answers recommend and be done with it.
If however you need to have a shared branch between two repos that are both in use you can achieve it with the following setup
Repo1 - will act as the server and also be used for development
Repo2 - will be for development only
Setup Repo1 as follows
Create a branch to share work on.
git branch shared_branch
To be safe, you should also create a $(REPO).git/hooks/update that rejects any changes to anything other than shared_branch, because you don't want people mucking with your private branches.
repo1/.git/hooks (GIT_DIR!)$ cat update
#!/bin/sh
refname="$1"
oldrev="$2"
newrev="$3"
if [ "${refname}" != "refs/heads/shared_branch" ]
then
echo "You can only push changes to shared_branch, you cannot push to ${refname}"
exit 1
fi
Now create a local branch in repo1 where you will do your actual work.
git checkout -b my_work --track shared_branch
Branch my_work set up to track local branch shared_branch.
Switched to a new branch 'my_work'
(may need to git config --global push.default upstream in order for git push to work)
Now you can create repo2 with
git clone path/to/repo1 repo2
git checkout shared_branch
At this point you have both repo1 and repo2 setup to work on local branches that push and pull from shared_branch in repo1, without needing to worry about that error message or having the working directory get out of sync in repo1. Whatever normal workflow you use should work.
OK, in case you want a normal remote repository, then create an extra branch and check it out. Push it into one branch (which is not checked out) and merge it with one which is currently active later after pushing from locally.
For example, on a remote server:
git branch dev
git checkout dev
On the local setup:
git push
On remote server:
git merge dev
Here is one test you can do to see how the bare server stuff work:
Imagine you have a workstation and a server with live site hosted on it, and you want to update this site from time to time (this also applies to a situation where two developers are sending their work back and forth through a bare middleman).
Initialization
Create some directory on your local computer and cd into it, then execute these commands:
# initialization
git init --bare server/.git
git clone server content
git clone server local
First you create a bare server directory (notice the .git at the end). This directory will serve as a container for your repository files only.
Then clone your server repository to a newly created content directory. This is your live/production directory which will be served by your server software.
The first two directories resides on your server, the third one is a local directory on your workstation.
Workflow
Now here is the basic workflow:
Enter the local directory, create some files and commit them. Finally push them to the server:
# create crazy stuff
git commit -av
git push origin master
Now enter the content directory and update the server's content:
git pull
Repeat 1-2. Here content may be another developer that can push to the server too, and local as you may pull from him.
Using this to push it to the remote upstream branch solved this issue for me:
git push <remote> master:origin/master
The remote had no access to the upstream repo so this was a good way to get the latest changes into that remote
I had to re-run git --init in an existing bare repository, and this had created a .git directory inside the bare repository tree - I realized that after typing git status there. I deleted that and everything was fine again :)
(All these answers are great, but in my case it was something completely different (as far as I can see), as described.)
I'm sure most people viewing this question will stop at the first two huge answers, but I'd still like to offer my solution.
I had an Eclipse + EGit web project setup when encountering the described error. What helped me was simply using the GitHub app, which seemed to magically resolve the issue. While EGit would always refuse the push, the GitHub desktop app would just shrug its shoulders and push my changes. Maybe it handles the multi-login-situation more gracefully.
An article I found that might be useful to others is Git in 5 minutes.
I had an Xcode project under Git version control that I wanted to push up to a Virtual Distributed Ethernet (VDE) I have in a DC. The VDE runs Centos 5.
None of the articles I read about Git talked about bare repositories. It all sounded so simple until I tried what I thought should be easy coming from an SVN background.
The suggestions here to make the remote repository bare worked. Even better for my requirements was to clone the Xcode project to projectname.git, copy that to the remote server; then pushes magically worked. The next step will be getting Xcode to push without errors about commits, but for now I'm okay doing it from Terminal.
So:
cd /tmp (or another other directory on your system)<br/>
git clone --bare /xcode-project-directory projectname.git<br/>
scp -r projectname.git sshusername#remotehost.com:repos/<br/>
To push changes from your Xcode project after you've committed in Xcode:
cd /xcode-project-directory<br/>
git push sshusername#remotehost.com:repos/projectname.git<br/>
I'm certain there is a smoother more sophisticated way of doing the above, but at a minimum this works. Just so everything is clear, here are some clarifications:
/xcode-project-directory is the directory your xcode project is stored in. It's probably /Users/Your_Name/Documents/Project_Name.
projectname is literally the name of the project, but it can be anything you care to call it. Git doesn't care, you will.
To use scp you need to have a user account on the remote server that's allowed SSH access. Anyone running their own server will have this. If you're using shared hosting or the like, you might be out of luck.
remotehost.com is the name of your remote host. You could as easily use its IP address. Just for further clarity I'm using Gitosis on the remote host with SSH keys, so I'm not prompted for passwords when I push. The article Hosting Git Repositories, the Easy (and Secure) Way tells you how to set all that up.
The best way to do this is:
mkdir ..../remote
cd ..../remote
git clone --bare .../currentrepo/
This will clone the repository, but it won't make any working copies in .../remote. If you look at the remote, you'll see one directory created, called currentrepo.git, which is probably what you want.
Then from your local Git repository:
git remote add remoterepo ..../remote/currentrepo.git
After you make changes, you can:
git push remoterepo master
I just ran into this problem with a deployment git repository on Heroku.
I don't know why Heroku has a non-bare repository on their side, but as a workaround I was able to reset the remote repository, and reupload.
You shouldn't use Heroku's copy of your repository as your only git repository for collaboration, but just in case, I'll say clearly: Do not do this unless you are sure you have a full copy of your repository stored securely somewhere other than Heroku. Doing a reset will delete the repository contents.
To reset:
Install the Heroku toolbelt (which contains the command line client) if you haven't already.
Install the heroku-repo plugin if you haven't already.
heroku plugins:install https://github.com/heroku/heroku-repo.git
Do the reset, which deletes the repository and creates a new, empty one
heroku repo:reset
Push to your Heroku remote as you normally would; it will reupload everything.
You will need to change the config file on the remote server once you have created empty(bare) repository, say
root#development:/home/git/repository/my-project# cat config
there you will see
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
You will make this bare to false to true and I removed logallrefupdates = true (not sure of its use!)
to
[core]
repositoryformatversion = 0
filemode = true
bare = true
You may test following
$ git remote show origin
* remote origin
Fetch URL: my-portal#development:/home/XYZ/repository/XYZ
Push URL: my-portal#development:/home/XYZ/repository/XYZ
HEAD branch: (unknown)
This HEAD branch: (unknown) will be shown if you are unable to PUSH. So if the HEAD branch is unknow, you should change bare to true and after push successful you can reuse the
git remote show origin
and you will see
HEAD branch: master
For me working solution is:
ON REMOTE:
git checkout -b some_tmp_name
ON LOCAL:
git push
ON REMOTE:
git checkout master
git branch -d some_tmp_name
But this is not the real solution it's just workaround.
Just in case someone finds it useful. For me it was a git server permissions issue. I checked out the project from the beggining and push a simple file and then I got the "Push rejected: Push to origin/master was rejected"
Let me add my 50 cents, because the most voted answer https://stackoverflow.com/a/3251126/3455918 suggests a converting of remote repw to a bare repository, and what if it's not what I want?
In the end I have to have the same code on the remote machine but not just blobs of bytes somewhere in .git limbo.
The second-voted (as of this writing) solution https://stackoverflow.com/a/2933656/3455918 does the job but after testing this out I ended up having to constantly switch between branches on the remote machine to "free" the branch I want to push from my local machine to.
This worked for me:
Another solution that worked for me so far is not mine, credit is given to a user #kxr who commented on the first solution.
On the remote machine you have to make this command in the repo directory.
git config receive.denyCurrentBranch updateInstead
After this you are done!
Obviously, there might be some drawbacks of this solution but for a simple task of synchronizing your local machine code to your remote repo it's probably good enough.
I would be grateful if someone explaines in comments why it's totally fine to create a brand new repo on github, link your local folder to it and start doing git push origin master without errors.
But trying to make this same thing with the repo on the remote server yields and error:
! [remote rejected] master -> master (branch is currently checked out)
With Git, two regular (non-bare) repositories can't push/pull files back and forth directly. There must be an intermediary bare repository. Apparently, it's sort of like a married couple who have a kid, and the couple is getting divorced. The parents won't talk to each other, but they will communicate through the kid.
So, you have one repository, you clone this repository to a bare repository, and then you clone that to a third. The first and the third can exchange information via the second repository, the bare one. I guess this makes sense, as you wouldn't want someone able to check stuff into your repository without your consent, as that could cause merge conflicts & the like.
So, here's an example:
On PC, in ~/workspace
git init
echo "line 1" > afile.txt
git add .
git commit -m ‘initial import’
git clone --bare . ../remote-repository.git
git remote add origin ../remote-repository.git
git push --set-upstream origin master
On laptop, in ~/workspace (do not do git init, etc.)
git clone //LJZ-DELLPC/remote-repository.git/ .
// Then make various commits, and push them:
echo "line 2" > afile.txt
git add afile.txt
git commit -m 'added line 2'
git push
Then back on PC, in ~/workspace
git pull
// Then make various commits, and push them:
git push
On laptop
git pull
and so forth..
Here's an absolute concrete example all on one machine, copied straight from the command window, so that we'll know that no steps were left out, that it really did work, etc:
lylez#LJZ-DELLPC ~
$ cd gitdir
/home/lylez/gitdir
lylez#LJZ-DELLPC ~/gitdir
$ ls
lylez#LJZ-DELLPC ~/gitdir
$ mkdir repo1
lylez#LJZ-DELLPC ~/gitdir
$ cd repo1
/home/lylez/gitdir/repo1
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git init
Initialized empty Git repository in /home/lylez/gitdir/repo1/.git/
lylez#LJZ-DELLPC ~/gitdir/repo1
$ echo "line 1" > afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git add afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git commit -m 'initial import'
[master (root-commit) f407e12] initial import
1 file changed, 1 insertion(+)
create mode 100644 afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git clone --bar . ../repo1-bare-clone
Cloning into bare repository '../repo1-bare-clone'...
done.
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git remote add origin ../repo1-bare-clone
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git push --set-upstream origin master
Branch master set up to track remote branch master from origin.
Everything up-to-date
lylez#LJZ-DELLPC ~/gitdir/repo1
$ cd ..
lylez#LJZ-DELLPC ~/gitdir
$ ls
repo1 repo1-bare-clone
lylez#LJZ-DELLPC ~/gitdir
$ mkdir repo1-remote
lylez#LJZ-DELLPC ~/gitdir
$ cd repo1-remote
/home/lylez/gitdir/repo1-remote
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ git clone ../repo1-bare-clone .
Cloning into '.'...
done.
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ ls
afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ cat afile.txt
line 1
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ echo "line 2" >> afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ git add afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ git commit -m 'added line 2'
[master 5ad31e0] added line 2
1 file changed, 1 insertion(+)
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 260 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /home/lylez/gitdir/repo1-remote/../repo1-bare-clone
f407e12..5ad31e0 master -> master
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ cd ../repo1
lylez#LJZ-DELLPC ~/gitdir/repo1
$ ls
afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1
$ cat afile.txt
line 1
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git pull
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ../repo1-bare-clone
f407e12..5ad31e0 master -> origin/master
Updating f407e12..5ad31e0
Fast-forward
afile.txt | 1 +
1 file changed, 1 insertion(+)
lylez#LJZ-DELLPC ~/gitdir/repo1
$ cat afile.txt
line 1
line 2
lylez#LJZ-DELLPC ~/gitdir/repo1
$ echo "line 3" >> afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git add afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git commit -m 'added line 3'
[master 3fa569e] added line 3
1 file changed, 1 insertion(+)
lylez#LJZ-DELLPC ~/gitdir/repo1
$ git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 265 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ../repo1-bare-clone
5ad31e0..3fa569e master -> master
lylez#LJZ-DELLPC ~/gitdir/repo1
$ cd ../repo1-remote/
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ ls
afile.txt
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ cat afile.txt
line 1
line 2
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ git pull
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/lylez/gitdir/repo1-remote/../repo1-bare-clone
5ad31e0..3fa569e master -> origin/master
Updating 5ad31e0..3fa569e
Fast-forward
afile.txt | 1 +
1 file changed, 1 insertion(+)
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ cat afile.txt
line 1
line 2
line 3
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
$ git --version
git version 2.1.1
lylez#LJZ-DELLPC ~/gitdir/repo1-remote
After checking out the branch of a colleague, at some point
I couldn't push or pull from remote.
Each time I ran git push or git push origin branch_name or those variant, I always got a everything up to date even though I had committed changes. Ultimately, what did the trick was git push -f origin HEAD:origin/branch_name. So my question is, why did I have to run this? what did I do to get there?
the fatal error I got was:
fatal: You are not currently on a branch.To push history leading to current (detached HEAD) state now, use: git push origin HEAD:<name-of-remote-branch>
Current State: Your head isn't attached to a branch, so you pushed with the branch whose history was the same as the remotes. You were working with a detached head, so when you pushed the head instead of the branch, it worked.
If you do a git status it with show:
HEAD detached at XXXXXXX
Fixing it:
Now that your remote has the changes you made, you can checkout the branch_name and pull your changes from remote. Your branch_name should already be tracking that remote branch.
Why you had to do this: You somehow detached your head. Without knowing the commands you used, we won't be able to tell you why you had to do this.
An example of how you could have done this:
#Don't do this, because force pulling will make you lose your work.
git checkout --detach
git pull --all -f #Don't do this.
You should probably edit (parts of) your last two ... er, now, three—comments into your question, but for now, I'll just quote them here:
I found where I might have off road. When I checked-out the branch I was going to work on, I got this message (let's called the branch b1:
Branch b1 set up to track remote branch b1 from origin.
Switched to a new branch 'b1'.
I checked-out the branch this way:
git checkout b1.
Then when I tried to push I did:
git push --set-upstream origin b1.
Branch b1 set up to track remote branch b1 from origin.
Everything up to date
OK, in that case you are probably fine.
git checkout
The problem you are running into here (well, in my opinion it's a problem) is that git checkout crams three or four (or more, depending on how you count) different things into one command.
Normally you would use:
git checkout somebranch
to check out (switch to) your local branch somebranch. Of course, that's great for branches you already have, but no good for branches you don't have locally yet. So Git crams another, different, command into git checkout: the "create new branch, then switch to it" command.
Normally this command is spelled git checkout -b newbranch. The -b flag means "create new". It's pretty reasonable to have this command spelled the same as git checkout, with just a flag, since we're switching to this newly created branch, but it probably would be clearer if it were a separate command, such as git create-and-then-switch-to-new-branch.
Now, pretty often, when you are creating a new local branch, you are doing so with the intent of having it "track" (as its "upstream") some existing remote-tracking branch, origin/b1 or whatever. In this case, you originally had to type in:
git checkout -b b1 --track origin/b1
which is still really obvious: create new branch b1, base it off remote-tracking branch origin/b1, and make it track (have as its upstream) origin/b1. Again, this might be clearer as git create-and-then-switch-to, but it's not so bad to have it shoved into git checkout, plus checkout is a lot shorter to type!
Now, many years ago (back in 2013 or so), the Git folks saw that this action was pretty common, and decided to make Git do it "magically" for you under certain conditions. If you write:
git checkout b1
and you don't currently have a branch b1 and you do currently have an origin/b1 and you don't have any other remote-tracking branch whose name ends in b1, then (and only then!), git checkout uses the create-and-then-switch-to-new-branch command, with the --track flag. So:
git checkout b1
means
git checkout -b b1 --track origin/b1
in this one special (but common) case.
--track means "set upstream"
Each branch (well, each named, local, branch) can have one (1) "upstream" set. The upstream of a branch has a bunch of uses: git status, git fetch, git merge, git rebase, and git push all look at the upstream. Having an upstream set makes git status show how many commits you are ahead and/or behind of the current branch's upstream. And, it lets you run all the other commands with no additional arguments: they can figure out where to fetch from, or what to merge or rebase, or what to push, using the current branch's name and its upstream setting.
Branches do not have to have an upstream, and a new branch you create doesn't, by default. Moreover, if it's a "very new" branch—one that does not exist on origin, for instance—there's no origin/name yet to have as an upstream in the first place. But when you create a new branch from a remote-tracking branch, setting the remote-tracking branch as the upstream of the new branch is almost always the right thing.
(Note: having an upstream also affects git pull because git pull is just git fetch followed by either git merge or git rebase. Until they are very familiar with Git, I think most people are noticeably better off running git fetch first, then git rebase or git merge second, depending on which one they want—and more often, that's actually git rebase, which is not the default for git pull: git pull defaults to using git merge second. Once they are familiar with the fetch-and-whatever sequence, then people can configure git pull to do the one they intend, and use git pull as a shortcut to run both commands. However, there are times to keep them separate anyway.)
For completeness
The other things that git checkout can do, that don't change the current branch, are:
copy files from the index to the work-tree: git checkout -- <paths>, including the special git checkout --ours and git checkout --theirs variations
copy files from specified commits to the index and then on to the work-tree: git checkout <tree-ish> -- <paths>
restore conflicted merge files to their conflicted state: git checkout -m -- <paths> (as with --ours and --theirs, this only works during a conflicted merge)
interactively patch files: git checkout -p (this variant gets especially complicated and I'm not going to address it further)
The checkout command can also "detach HEAD" (see previous answer below) and create "orphan" branches, but both of these effectively change your current branch, so they don't fall into this special "non-branch-changing" class of checkout operations.
So what happened with the first git push
When you ran:
git push --set-upstream origin b1
you told your Git to contact the other Git on origin, give it the commit ID to which your branch b1 pointed, see if it needed any of those commits and files (it didn't), and then ask it to set its branch name b1 to point to the same commit.
Now, you'd just created your own local b1 from your origin/b1, which you recently git fetch-ed from origin, so your b1 already pointed to the same commit (you did not make any new commits) and hence your git push gave them their own commit hash back and they said "Well, gosh, that's what I already have! We're all up-to-date!" And then their Git and your Git said goodbye to each other, and your Git carried out your last instruction: --set-upstream.
This changed the upstream of your local branch b1 to origin/b1. Of course, this was already the upstream for your local branch b1, so that was not a big change. :-) But your Git did it anyway, and then reported that everything was still up to date.
Earlier answer (was mostly done when you added your third comment)
... I had one file committed with changes. git status didn't return nothing after I committed.
git status should always print something, such as (two actual examples):
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
or:
HEAD detached at 08bb350
nothing to commit, working directory clean
In this second case, you are in "detached HEAD" mode. This special mode means you are not on a branch—or it may be more accurate to say that you are on the (single, special-case) anonymous branch that goes away as soon as you get on any other branch.
Any commits you make while in detached HEAD mode are perfectly fine, normal commits—except that there is no branch name that will make them permanent. This means these commits can go away once you switch to some other branch.
All my attempts to push were unsuccessful.
Again, actual git push output might help here, so one could tell why the push failed or did nothing. If it complained about being in "detached HEAD" mode, that would be significant: we would know that you were in the detached HEAD mode.
git fetch -a didn't return nothing as well.
(Just an aside: It's a bit odd to use -a here: that flag is almost never useful to humans and is intended more for scripting purposes. It just makes your fetch append to FETCH_HEAD rather than overwriting it. The special FETCH_HEAD name is meant for scripts to use.)
the last step I had were to git checkout origin/branch_name.
This will take you off whatever branch you were on before, and put you in "detached HEAD" mode. If you used to be in "detached HEAD" mode, it will abandon your previous anonymous branch and put you on a new, different anonymous branch.
Any commits you made while on the previous anonymous branch are ... well, not lost, precisely, but are now difficult to find (and set to expire after 30 days).
When I tried to push from there I got the following message:
fatal: You are not currently on a branch.
To push history leading to current (detached HEAD) state now, use:
git push origin HEAD:<name-of-remote-branch>.
Which I did [... HEAD:origin/branch_name] and it worked
Yes, but alas, this did nothing useful, because you are now on an anonymous branch that is exactly the same as origin/branch_name. This ends up asking the remote to create—on the remote, as a local branch there—the name origin/branch_name. That's probably not a good idea, since having a local branch named origin/branch_name is like having a bicycle named "motorcycle". If you also have a motorcycle and ask your friend to bring you "motorcycle", which will he bring you, the bicycle named "motorcycle", or the motorcycle?
I just bought a new machine, and I'm working on a new github repo. I clone it into my machine using
git clone git#github.com:<username>/<exact-repo-name>.git
and it clones fine:
Cloning into '<exact-repo-name>'...
remote: Counting objects: ###, done.
remote: Total ### (delta 0), reused 0 (delta 0), pack-reused ###
Receiving objects: 100% (###/###), ### KiB | 0 bytes/s, done.
Resolving deltas: 100% (###/###), done.
Checking connectivity... done.
And, I add all of the remote branches locally by doing:
for remote in git branch -r; do git checkout -b $remote; done
Then, when I try to pull from any of the branches, using
git pull origin/<branch-name>
I get the ever-so-common error:
origin/<branch-name> does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
So, I go through all of the steps:
ssh -vT git#github.com
ssh-add -l
eval "$(ssh-agent -s)"
These all succeed, and I check the output of ssh-add -l and I see that it is in the list ssh keys on my github account. I go into Settings -> ssh keys, and I see the agent there.
Are there certain user permissions that are on top of those for ssh?
I agree with #Felix that this most likely is not an SSH problem, though it might be masquerading as this. Instead, I think you have a problem with your path. You can try running git clone like this:
git clone https://username#github.com/username/exact-repo-name.git
Here the username is your GitHub username. Git will prompt you for a password so you don't have to enter it as plain text. Please read this SO article for more information.
It's probably not an ssh issue, as an ssh problem would normally result in a message like
fatal: The remote end hung up unexpectedly
Most likely it's a path problem: either you have an extra slash or space in the remote path (or if there's supposed to be a space, you're missing quotation marks in your command line), or some letter is the wrong case. Double-check the rest of the URL. It could also be exactly what it says, a permissions problem -- are you sure you're connecting as the right user for this repository?
Edit: from your added details, it looks like you're just getting the syntax of the pull command mixed up. Does it work if you do this?:
git checkout <branch-name>
git pull # Edit: don't do this without reading all of 'git help pull'
? Also, does git fetch --all work? (git pull is just git fetch followed by git merge.)
Further edit: I can reproduce your error; it is a command syntax problem. Here are more examples:
"source" is a git repository in a local folder; I clone it into a folder called "dest":
$ git clone source dest
$ cd dest
Now I do the git branch command in your for loop:
$ git branch -r
origin/HEAD -> origin/master
origin/branch1
origin/branch2
origin/master
I would expect that first line to cause problems, since that would result in these commands being run in your for loop:
git checkout -b "origin/HEAD"
git checkout -b "->"
...
(Note that your example is missing backticks around `git branch -r`, so if what you posted is literally what you're running, you'll end up with branches called "git", "branch", and "-r", which would really not be what you want... if you had trouble putting backticks into inline code blocks, see https://meta.stackexchange.com/questions/55437/how-can-the-backtick-character-be-included-in-code)
Then if I try your pull command, I get the same error as you:
$ git pull origin/branch1
fatal: 'origin/branch1' does not appear to be a git repository
fatal: The remote end hung up unexpectedly
This is because git pull takes the remote repository name (origin) and the remote branch name (branch1) as two separate parameters, separated by a space. So this works:
$ git pull origin branch1
From /tmp/source
* branch branch1 -> FETCH_HEAD
Already up-to-date.
But, that's probably not quite what you want, because it sounds like you wanted to create a bunch of local branches to track the same named branches on origin (e.g. you want a local branch named "branch1" that tracks "origin/branch1"). Your local branch creation commands didn't include setting up tracking, so what you've actually got is a local branch called "origin/branch1" and a branch on remote repository "origin" also called "branch1", i.e. after running your for loop, the output of git branch -a is:
$ git branch -a
master
origin/HEAD
origin/branch1
* origin/branch2
origin/master
remotes/origin/HEAD -> origin/master
remotes/origin/branch1
remotes/origin/branch2
remotes/origin/master
...So there are two branches called "origin/branch1", and the only thing that differentiates them is that in one case, the repository is your local one and the branch's literal full name is "origin/branch1", and in the other case, the repository is the remote one (named origin) and the branch's literal full name is "branch1", which is notated as "origin/branch1" -- this will probably be very confusing to work with (and in some commands, git will complain and say, "origin/branch1 is ambiguous" and you'll have problems).
Note also that each of the new branches your for loop created is actually just a copy of master (or whatever the default/selected branch was on origin), because you didn't specify a remote branch for them to start from. That is, in your clone command, your local repository was set up with one branch selected (probably master). You then told git "make new branch from where I am now" for each line in your for loop, so each of those new branches, despite having all the different names of the branches on remote, are references to the first branch selected with your clone. This is probably not what you wanted.
I think what you actually wanted was this command, run for each remote branch:
$ git checkout --track origin/branch1
Branch branch1 set up to track remote branch branch1 from origin.
Switched to a new branch 'branch1'
Actually, if you've just done a fresh clone, a git checkout branch1 [without the -b] will have the same effect I think -- since there is no local branch called branch1, git will look for one in the repository you cloned from and set up tracking if it finds one.
...So I guess what this whole post boils down to is:
Leave out the -b in your initial checkout commands
Use a space instead of a slash in your pull command
:)
See https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches and the output of git help pull for more about remote tracking and pulling; some of it is a bit subtle (even more so than all the caveats I mentioned :) ).
Nowadays, I see a lot of commits from Linus Torvalds and/or Gitster that look like so:
Merge branch 'maint' of git://github.com/git-l10n/git-po into maint …
* 'maint' of git://github.com/git-l10n/git-po:
l10n: de.po: fix a few minor typos
or:
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upst… …
…ream-linus
Pull MIPS update from Ralf Baechle:
...
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (22 commits)
MIPS: SNI: Switch RM400 serial to SCCNXP driver
...
I have no idea how would one do that, although, I know about the git remote and git checkout and git merge that I use to merge forks (or "pull requests") but it does not generate such message, why? and how would someone do that (provide examples please)?
P.S: I'm a fan of Linus Torvalds commits etc, like how detailed the description of his merges look ;P
P.S: This is how I used to merge stuff:
git remote add anotherremoot
git checkout -b anotherbranch
git pull remoteshortcut
...do tests...
git checkout master
git merge anotherbranch
git push
The above example I learned from: http://viget.com/extend/i-have-a-pull-request-on-github-now-what
Just use git pull to pull the remote branch into master:
git remote add something git://host.example.com/path/to/repo.git
git checkout master
git pull something master
Or do it without adding a remote:
git pull git://host.example.com/path/to/repo.git
git pull fetches the remote branch, and merges it into the local branch. If possible, it does a fast-forward merge, which just means that it updates the current master to the latest commit without generating a merge commit. But if there are changes on both sides, it will do a merge, like the ones you see Linus and Junio doing, with the remote URL included.
If you want to guarantee that you get a merge commit, even if it could fast forward, do git pull -no-ff. If you want to make sure that pull never creates a merge commit (so fails if there are changes on both sides), do git pull --ff-only.
If you want to include a more detailed message, like the full log that Linus provides, do git pull --log. If you want to edit the message, instead of just using the automatically created message, use git pull --edit. See documentation for git pull for more options.