how to change branch on --bare remote from local in git - linux

I am trying to make a hook on a remote --bare repository that will copy the source code I send from a local git, in different folders according the branch I'm sending to. I have 3 branches on local: master, development and release so I wish that on the remote would be 3 folders containing the source code of each branch. I found that using:
git rev-parse --abbrev-ref HEAD
in combination with a series of if conditions could do the trick. The only problem is that the HEAD remains the same on remote for whatever branch you send to. Is there any code that could be used in the hook, so it would know that I am sending to a certain branch? Or is there any other method for doing this? Thanks!

Your one bare repo will have all 3 branches on it. You can use git modifiers like this to make 3 separate directories update to what each branch contains:
git --work-tree=/some/project/dir/branch1 --git-dir=/path/to/bare/repo checkout branch1 -- .
To avoid specifying those options, you can set their corresponding environment variables:
GIT_WORK_TREE
GIT_DIR
This way you can keep one bare repo and 3 separate directories that update when branches are pushed. Remember what the arguments are that are provided in your hook. The first is the branch name.

Related

How to pull from specific branch in git- understanding gap

I am using gitlab and really confused in few things. :
When we create new branch by git checkout -b test. Does it create copy of master or it creates copy of branch i am currently in?
For example: I am currently at branch dev, then i write command git checkout -b test. So it will be copy of dev, not masters?
Pull : when we write git pull , it pulls changes of current branch from remote branch of same name. Its used when more people are working on same project.
Example : I am at branch dev, i write git pull, it updates my local as of dev in remote. Now i created a new branch test, checkout test branch and do git pull. It gives me :There is no tracking information for the current branch.
Please specify which branch you want to rebase against.
its because there is no test branch in remote ?
What command to be used if i want to pull from dev branch while my current branch is test? is it git pull --rebase dev test?
When we write git push, it pushes current branch to remote one.
example : i am on branch test, i add, commit and write git push. It simply pushes my branch test to remote with same name as test.
Can we push to specific branch like push test to dev?
What is difference in following considering i am at branch test:
git push
git push origin test
they both push to remote?
My requirement is : there is branch dev which is not master branch, i am supposed to work on this branch as starting and end point. Like, new branch should be copy of this and i am supposed to push to same branch.
Does it create copy of master or it creates copy of branch i am currently in?
It creates a new branch named test based on the current branch, whatever that might be, as a starting point.
What command to be used if i want to pull from dev branch while my current branch is test?
I believe you can pull any branch you wish into your current branch. E.g. if you were on branch test and wanted to pull dev you could just use:
git pull origin dev
Can we push to specific branch like push test to dev?
Yes, can specify both the local and remote branch names when pushing, e.g.
git push origin test:dev
1- When you do git checkout -b test it creates copy of your current branch(in this case 'dev').
2- git pull will only sync your changes between remote and local. If you upload the branch and try to pull, it does not work because your local and remote changes will be synchronized.
3- This could help you : Make an existing Git branch track a remote branch?.
If you want to work in a copy of a branch, you should do this:
git checkout <origin_branch> (master, dev, what u want )
git checkout -b <work_branch> (test, for example. This create a copy of your origin branch)
After this, you have a new branch 'test' in your local repository. If you want to push this branch on the repo:
git add .
git commit -m "Pushing new branch test"
git --set-upstream origin <your_new_branch>

why did I have to run this git command?

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?

remote git repo cannot be auto checkout after a merge hook

I have a remote non-bare git repo, which is my static blog site.
I push a commit in local master branch to the remote master branch every time, and there is a post-update hook, which is like below:
echo "hook..."
git merge master
echo "after hook..."
In the remote repo, there is a pages branch which is checked out by default, what I want is that pages branch keep update of the master branch and auto checkout to workspace.
However, workspace cannot be checkout automatically, but the two branch has been updated.
In sum, What I want is the workspace can update after the pages branch merged every time. So that my website can update too.
==========detail process===========
==local repo:
*master
==remote repo:
*pages
master
git push local-master ---> remote-master [OK]
trigger hook do : git merge master to pages branch (which is checked out) [OK]
workspace updated (this is what I want) [NOT-OK]
Considering the current working directory of such an hook is the .git/ folder itself (ie, GIT_DIR is set to '.', which in non-bare repo is .git/), try a .git/hooks/post-receive with:
unset GIT_DIR
cd ..
git merge master

`ssh -vT git#github.com` works fine, and agent is in github ssh keys. Where is the issue?

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 :) ).

Git merge branch of another remote

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.

Resources