As Lasse V. Karlsen said in a comment, nothing happens in the first case because you are not pushing any update to your remote.
When you run git push
, you are telling your Git to call up another Git over the Internet-phone and give it some items and/or instructions. You had two examples: git push remote_repo master
and git push remote_repo branch_from_previous_commit
. Let's take the first one first.
The complete sequence you used was:
git checkout <sha1_of_previous_commit>
git push remote_repo master
The first step gets you what Git calls a detached HEAD, which just means that you are not on a branch now, so that any new commits you make will be made without changing any of your existing branches. You didn't make any, so this does not matter yet, and then you told your Git to tell their Git about your master
branch, which means that whatever your current branch is—or in this case, isn't—still doesn't matter.
Your Git calls up their Git—your server's Git, in this case; let's call it S for server—and your Git tells S: "please set your, S's, master
to commit somehash" (where somehash is whatever hash ID is stored in your name master
). S checks his master
and it's already set to that hash,1 so S does nothing at all and says "OK, all done!"
Your second sequence does a bit more:
git checkout <sha1_of_previous_commit>
git checkout -b branch_from_previous_commit
git push remote_repo branch_from_previous_commit
Here, your first command detaches HEAD as before, but your second command creates a new branch name in your own repository, pointing to the current commit, which is the one you checked out in your first command. (Incidentally, you can combine these two as git checkout -b <name> <hash>
.)
This time, your Git calls up S as before, but instead of saying "please set your master
to hash", it says "please set your branch_from_previous_commit
to hash." Presumably, S doesn't have such a branch yet; because you are using Git version 1.9, or have configured your later Git to act like your older Git, your Git winds up telling S to create that branch. Equally presumably, S does create that branch, i.e., this push succeeds. Now we must see what happens on the other machine, i.e., what is happening from S's point of view.
(For more details that are mostly irrelevant to your immediate problem, see What does GIT PUSH do exactly?)
1I am making another assumption here, that you successfully pushed your master
earlier, or have made no commits to your master
.
As seen on S
Your server S is quietly humming along when the Git-phone rings.2 Ring-ring! Ring-ring! S answers, and it's a call from someone claiming to be you. This other Git says "Hello, please set your branch_from_previous_commit
to somehash." You (S) check that this is OK, which it is, so you create a new reference, refs/heads/branch_from_previous_commit
, set to somehash. You then see that you have a post-receive
hook, so you run it, feeding it this line (all as one line—I broke it into three for display purposes) on its standard input:
0000000000000000000000000000000000000000
somehashsomehashsomehashsomehashsomehash
refs/heads/branch_from_previous_commit
The all-zeros value is an indicator: "this reference is new". The nonzero value is the new hash. The reference name, refs/heads/branch_from_previous_commit
, is the full name of the branch: the post-receive script can tell that it's a branch name because the name starts with refs/heads/
, and can get the branch name by stripping off that refs/heads/
part.
If your phone call had asked you to create a tag, the full name would be refs/tags/sometag
; if it asked you to create six branches, update three more branches, create one tag, and delete two branches, you would feed all twelve names into the post-receive script, with their old and new hash IDs. The old hash ID is all-zeros if the name is new; the new hash ID is all-zeros if the name is being deleted; and otherwise both hash IDs are nonzero and they are the old and new values of an updated branch or tag.3
You have not shown us your script, so now I must guess Edit: you added a comment with your script, which reads:
git --work-tree=/var/www/html/site.com --git-dir=/path/to/remote/bare checkout -f
(without even reading from standard input). This script is wrong.4
The git checkout
command takes options, including -f
or --force
, but also including branch names. What branch name does this script supply?
If a git checkout
command is given no branch name, what branch does Git check out? Click on the documentation link to see the following text:
You could omit <branch>
, in which case the command degenerates to "check out the current branch", which is a glorified no-op with a rather expensive side-effects to show only the tracking information, if exists, for the current branch.
What is the current branch? Remember, we are server S, working in our Git repository. We are not the client. We are answering the Git-phone and we have our own repository, with its own branches and its own HEAD. What is in our HEAD?
Probably, our HEAD
contains the branch name master
. So we will check out our master
again, doing (as the documentation says) an expensive kind of no-op. The fact that we just received a request to create a new branch branch_from_previous_commit
is quite irrelevant: we were told to check out the current branch, so we did.
Note that if we received a request to change our master
to a new, different hash, we would have verified that this was OK to do, then done it (provided it was OK), and then run our post-receive
script which would check out our (updated) master
. That would actually do something. But that's not what we got, and not what we did.
Hence, what you will need to do is at least one of these things:
Modify the post-receive script: understand what it means to deploy different branches. This is more difficult than it looks, because each Git repository has one main index, and Git assumes that the index matches the work-tree. If you set up multiple deployment work-trees, you must set up multiple index files for each such tree, or otherwise invalidate the index.
Use a push that modifies the master
branch.
Change the current branch on the server. If the deployment command is git checkout
without a branch name, it will deploy the current branch. If you somehow change that, it will deploy a different commit. How to have that happen is a different problem, but note that git checkout <branch-name>
changes the current branch (while also checking out that branch's tip commit). This may affect you if you choose to fancy up the deployment script.
In any case, it's probably wise to fancy up the deployment script at least a little bit, to scan through which branch(es) and/or tag(s) are being updated, and run the checkout-to-deploy only if the to-be-deployed branch has changed. This is not required, but it is a good idea if your server will retain multiple branches and/or tags, only one or some of which are to be deployed.
2Actually, it's probably the ssh-phone, or the https-phone, and something else answers and eventually, after deciding that it is you, hands the phone off to Git. But we don't need to worry about that.
3Tag updates require --force
, since Git 1.8.2 anyway. Branch updates require forcing if and only if they are non-fast-forwards. Besides these built-in rules, your pre-receive
and update
hooks can reject all (pre-receive) or selected (update) reference changes if you like.
4Or at least, sub-optimal, though it will get the job done initially.
post-receive
command for previous commit. So that remote /path/to/site directory will be checked out with previous commit.post-receive
script isgit --work-tree=/var/www/html/site.com --git-dir=/path/to/remote/bare checkout -f
– Shagbark/www/public/folder
and you do have a/www/public/folder/.git
subfolder, that makes/www/public/folder
a non-bare repo to which you can push to directly (provided you have Git 2.4+ on that remote server, and configured it to use the "push to checkout" setup. – Persevere