Gitolite: calling VREF for all but one repo - gitolite

I have the following setup. I want to check that commits have a certain commit message format (line limit, etc.). I want this for all repos, but one or two.
How can I tell this gitolite without having to define a group #check_msg that contains most repos. This would be cumbersome...
In my BADCOMMIT VREF, I already included some lines to not check the message if it is called with NOCHECK.
Any ideas??
repo testing
RW+ = #all
? VREF/BADCOMMIT/NOCHECK = #all
repo #all
- VREF/BADCOMMIT = #all
repo gitolite-admin
RW...

Instead of using git notes, I suggest you do this:
repo testing
RW+ = #all
option badcommit.nocheck = 1
repo #all
- VREF/BADCOMMIT = #all
Then, at the start of the VREF, you say
gitolite git-config -q $GL_REPO gitolite-options.badcommit.nocheck && exit 0
Much cleaner, and the knowledge of the exceptions stays within gitolite.conf.
(Assuming v3 of course).

Considering:
that a VREF has no idea of the git repo name or path it is called from, adding:
fallthrough means success (which means, as matt comments, that it will check all the VREFS)
The only solution seems for the VREF script "BADCOMMIT" to somehow detects it is in a git repo it should not test.
If, by convention, said git repo were to contain a **git notes (**which you can add at any time, without changing the git history, see man git notes) with a certain title on this note, it could decide to not go on with its check.
Since there are few git repos which shouldn't be tested with BADCOMMIT, you could add a note to the first commit of that repo.
That way, you don't need a NOCHECK, and you don't need to stop after a certain rule.

Related

Remove one specific empty git commit with command-line tool

For a nodejs command-line tool I add an empty commit to a repo and then want to remove it later.
Later I have at least 3 commits. The first one is a merge commit, the second one is the empty one I created and the third one is likely one from another now merged repo. Now that my tool has done it's task I want to remove the empty commit.
git rebase --onto emptyCommitID^ emptyCommitID
resulted in: fatal: Does not point to a valid commit 'emptyCommitID^'
(since the ID is the correct one I assume the commit is invalid due to it being empty)
git rebase --keep-base --onto thirdCommit^ headCommit
resulted in fatal: cannot combine '--keep-base' with '--onto'
trying rebase -i HEAD~3 after the tool had done it's main job resulted in:fatal: invalid upstream 'HEAD~3' which might be due to either the empty commit or the merged unrelated histories idk.
I do not want to use git filter-branch --prune-empty, because the tool shall leave other potentially empty commits untouched.
(The tool is for merging repos with unrelated histories. I create the empty commit so that files are staged when merged instead of committed directly which also happens when the --no-commit flag is set in an just initialized repo without prior commits)
maybe it is possible to solve this with git rebase --interactive, but I had the described problem with the invalid upstream and view this as very difficult to implement with a command line tool, mostly using exec to execute it's commands. Do you know a solution?
I think git rebase --onto emptyCommitID^ emptyCommitID should work.
fatal: Does not point to a valid commit 'emptyCommitID^' means that the emptyCommitID has no parent. It contradicts that the second one is the empty one and the first one is its parent.

error: failed to push some refs to 'git#github.com:<name>/<project>.git'

Hi I'm a total newbie using git I read a few StackOverflow Q&A on this error but didn't understand how my problem relates to others with the same error message. So I didn't dare to chance it and loose 6 hours of work that I need to push to my remote GitHub repo.
.
1.) The Beginning
So my code in the local working directory got broken and I couldn't figure out what the problem was. So I wanted git to go back to the latest working version of my project. I then found this tutorial and managed to get my local project to go back to a working version.
https://www.git-tower.com/learn/git/faq/restore-repo-to-previous-revision
$ git reset --hard <SHA-1 HASH NUMBERS>
.
2.) Trying to push
These are the commands I usually follow when I want to push local code to my remote repo.
# Pushing Changes - Staging
$ git diff
$ git status
$ git add -A
$ git status
$ git commit -m "Modified multiply function."
# Pushing Changes - Repository
$ git pull origin master
$ git push origin master
.
3.) The error
I don't understand what the error message is trying to tell me. Can somebody help me by showing what sequence of commands I need to run to be able to push code like usual again?
penguin#linux$ git push origin master
To git#github.com:<name>/<project>.git
! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'git#github.com:<name>/<project>.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Let's address this rather long comment (which I should do in another comment, but this won't fit at all so I'm answering a different question, namely, "how does detaching and reattaching HEAD work"):
Tnx torek I managed to force away that error with the link you provided. I also had some detached HEAD issues which I got rid by following Razan Paul's post here Fix a Git detached head? But all my changes while in detached HEAD mode was lost after the fixes. I have copies so I can just recreate them manually I guess. So in the future when I want to go back to the latest working version on my local working directory. What procedure will suite my situation best? I see so many different suggestions I don't know what's best for me
(incidentally, when addressing a comment to someone in particular you may want to use the #<name> syntax so they get alerted).
What you need is a proper Git book. The best free one is, in my opinion, the Pro Git 2 book. (There are not many, if any, other free ones so "best" could be vacuously true here. :-) ) A shorter, non-book reference that I find helpful is Think Like (a) Git, because Git is built atop some very simple bits of graph theory—but unless you know this, and until you realize this, you're stuck in this xkcd cartoon.
(I even have my own start on a book, but I have very little time to work on it these days.)
There are many work-flows you can use in Git. The first thing to remember, though, is that Git's "unit of storage" as it were—the thing it desperately tries to protect, so that you can get it back—is the commit. That's why you were having trouble pushing: you were telling some other Git: throw away some commits. Git does not want to do that.
Commits are uniquely identified by their hash IDs. These hash IDs are not very useful to humans, so Git gives us things like branch names to remember particular IDs—but in some cases you may have to resort to raw IDs, which you can cut and paste with your mouse, for instance.
Git's desire to keep commits around means that when you make commits using a detached HEAD, Git tries to keep those too. It will do so for, by default, at least 30 days. You can find the hash IDs using git reflog. If you use git reset --hard to make Git "forget" commits that were on a branch (rather than a detached HEAD), Git keeps those IDs around for at least 30 days as well, on the branch name's reflog. There's one reflog for each branch name, and one for HEAD itself.
Last, an attached HEAD—attached being the opposite of detached—is when you are, as git status will say, "on" some particular branch:
$ git status
On branch master
...
In this case, the branch name master is how Git actually identifies which commit you have checked out right now; and the name HEAD is simply attached to the name master.
To make this all work right, Git works backwards.
A brief introduction to graphs
To really comprehend what all this means, you need to draw the commit graph. Remember that each commit has its own unique hash ID—those big ugly 40-character-long strings of a hexadecimal number, like 5be1f00a9a701532232f57958efab4be8c959a29—but that's kind of unweildy, so you might want to just use single letters for small drawings:
A <-B <-C <--master
This is a pretty-new repository with just three commits in it. We made A first, then we made B, then we made C. (We'll run out of names for commits when we get to our 27th commit, so you can see why Git uses longer hash IDs.)
Since Git works backwards, the name master identifies, not commit A, but rather commit C. We say that the name master points to C.
Commit C, being our third commit, has inside it the name—the hash ID—of our second commit, commit B. We say that C's parent commit is B. So commit C points to B. Likewise, B has inside it the hash ID of commit A, so B points back to A.
Commit A was the first commit. It can't point back to a previous commit, so it just doesn't. This makes commit A special: it's a root commit. Every non-empty repository has at least one of these, the first commit ever made.
When you run git log, Git will start with your current commit—commit C, here—and work backwards: it shows you C, and then since C points back to B, Git shows B too. Since B points back to A, Git shows A as well; but A is a root commit, so Git can stop.
How branches grow
Since we're on master, let's make a new commit D. We'll do whatever we want with the source, git add files, and run git commit to create D.
Where will D point back to? Well, obviously it has to point back to C. So Git makes D have a parent commit of C:
A <-B <-C <-D
Git's final step here is to change the name master so that it holds the hash ID of commit D, giving us this picture:
A <-B <-C <-D <--master
Note that all the arrows necessarily point backwards. Moreover, all the arrows that are inside commits are frozen for all time: D points back to C, never anywhere else. The only arrow that changes is the one coming out of the branch name! So I tend to draw them without the internal arrows, to save space and make it fit better:
A--B--C--D <-- master
This is another key to understanding Git: branch names move, over time. Branches acquire new commits, and the names point to the last commit on the branch—what Git calls the tip commit. Git uses this tip commit to find the next-older commit for that branch: the tip's parent. Git uses that commit to find its previous commit, and so on, all the way back to the root commit.
The name HEAD normally just identifies a branch name
Let's complicate-up the above repository by adding a branch coming out of C:
A--B--C--D <-- master
\
E <-- develop
Here, we now have two branches. The name develop identifies commit E, whose parent is C. If we now run:
git checkout master
we'll be on branch master, as git status will say; if we create a new commit F now, its parent will be D. If we instead git checkout develop and create a new commit F, its parent will be E instead. So Git needs to know: which branch are we on? This is where we need to draw in the name HEAD:
A--B--C--D <-- master (HEAD)
\
E <-- develop
or:
A--B--C--D <-- master
\
E <-- develop (HEAD)
When your HEAD is attached like this, it's attached to a branch name. When you make new commits, Git will change the branch name so that it points to the new commit you just made.
A "detached HEAD" simply holds the commit hash ID directly
If you find yourself in detached HEAD mode, it's usually because you checked out an older commit directly. For instance, let's check out commit B, while keeping everything we have:
A--B <-- HEAD
\
C--D <-- master
\
E <-- develop
I had to bend the graph lines around to fit HEAD in, but now HEAD points directly to commit B.
If we now make a new commit F, its parent will be B, and Git will make HEAD point directly to F:
A--B--F <-- HEAD
\
C--D <-- master
\
E <-- develop
Note that whenever Git creates a new commit, the commit to which HEAD points—directly, if detached, or indirectly, if attached to a branch name—also changes! The new commit's parent is always whatever was HEAD just a moment ago, and now HEAD is the new commit, which is once again the current commit.
(This is also why parents don't know their children's hash IDs, but a child does know its own parent's ID. Git has to work backwards, because children know their parents: the parent commits exist when the child is created; but parent commits—which are read-only and frozen in time—don't know what children they will acquire in the future.)
As soon as we re-attach HEAD, though, we "lose" the ID of commit F:
A--B--F <-- ???
\
C--D <-- master (HEAD)
\
E <-- develop
Who remembers F's ID? The answer is: only the reflogs.
If you want to hang on to commit F, you should find its ID in your reflogs and attach a name to it—a branch or tag name, usually:
A--B--F <-- newbranch
\
C--D <-- master (HEAD)
\
E <-- develop
Now newbranch remembers the ID of F. If you'd made two commits, F and G, while you had a detached HEAD, you'd have to find the later one somehow and make sure your name points to G, so that you have:
G <-- newbranch
/
A--B--F
\
C--D <-- master (HEAD)
\
E <-- develop
and not:
G <-- ???
/
A--B--F <-- newbranch
\
C--D <-- master (HEAD)
\
E <-- develop
This is why making a lot of commits on a detached HEAD is not a great idea: it can be really hard to tell, from hash IDs, which commit is the tip-most.
The git it clearly mentioning that the current branch in which your working is not updated with remote repository as others have committed their code to that repository.
First you need to take a pull of remote repository and then commit your code
NOTE : Here origin is your remote repository location which you
might have added
Eg: Considering that your working on master branch
git pull origin master /* To update with the remote repository */
git push origin master /* To push your updated code */

Git: Commits that stick-out of master without being in a branch

I've been working on a project for some time using a git local repository for version control.
I have two branches in the repository: master and "other" (not its real name).
When I run git branch I get this list:
other
* master
Looking at my repository graph with gitg (a Gnome GUI for git), selecting "all branches" from the branches drop-down list, I get this graph:
I see the two branches, but there are also two commits, tagged "v1.2y" and "v1.2s", that stick out of the master branch and don't seem to merge back into it. They seem to be hanging there like non-merged-back branches, but they are not actual branches. At least neither git nor gitg list them as being branches.
Can someone explain to me the reason they stick out of the master branch if they are not branches themselves?
Please don't just simply tell me what to do to make it normal but, most importantly, the reason why this happened to begin with.
EDIT: I have never made a rebase or force push.
First of all, you can read about the difference between tags and branches here:
How is a tag different from a branch? Which should I use, here?
Suppose you do the following:
git checkout master //go to branch master, say at commit x
git checkout -b newbranch //create a new branch called newbranch that also points to x
git commit -a -m some_branch_commit_1 //add a commit to newbranch
git tag tagged_my_commit //tag your commit
git checkout master //go back to master
git commit -a -m "Something" //add a commit, say y to master
git checkout newbranch //go back to newbranch
git rebase master //create a copy of the commits on newbranch so that they now split of from y instead of x
In this case, a new copy of commit some_branch_commit_1 will be created. However, the old one still exists (it was tagged tagged_my_commit) so it will never disappear.
Basically, you now have two copies of the same commit, one of them is not on a branch with a particular name.
Suppose however you didn't tag that commit, then in principle it could be removed by git. However, deleting such commits (garbage collection) only happens from time to time. This can explain why commits that shouldn't keep on existing still are in your repostiroy. If you want to read more, see https://git-scm.com/docs/git-gc
As noted in the comments, this does not only happen with rebases. Any form of rewriting (e.g., amending commits, changing the pointer of a branch, ...) can lead you to this situation.
EDIT as requested: another example
git checkout master //go to master, say at commit x
git commit -a -m "I did something" //create a commit, say y1
git tag tagit //tag your commit
your history now looks like this
y1 = master = tagit
|
x
Now do the following
//edit some file
git commit -a -m "I did something (more)" --amend //change commit y1 such that it now also takes changes to the other file into account, say this is y2
In that case your history looks like this
y1=tagit y2=master
| /
| /
| /
| /
| /
| /
| /
| /
x
which seems to be like in your situation

Gitolite Update Hook exclude a repository

I'm adding a gitolite update hook as a VREF and was wondering if there was a way to apply it to all of the repositories except for the gitolite-admin one.
Having a simpler way rather than listing all of the repositories I want to apply the hook on would be great.
Currently I have:
repo #all
- VREF/update = #all
I was thinking of adding an exception above that one for the gitolite-admin repository.
Something like:
repo gitolite-admin
RW+ VREF/update = #all
repo #all
- VREF/update = #all
Is there a way to get a rule like this to work? Thanks for the help! (I tried this way and it didn't seem to work)
Just for other readers less familiar with VREF (introduced with "g3" or Gitolite V3).
The idea behind VREF rules are:
For every refex starting with VREF/FOO/ in a rule that applies to this user, a call to a program called FOO is triggered.
Note that the program isn't even called if the VREF rule doesn't apply to that user.
This is why one can define an 'update' hook even though the update hook is reserved by gitolite.
A normal update hook expects 3 arguments (ref, old SHA, new SHA).
Any VREF will get those three, followed by at least 4 more. Your 'update' VREF should just ignore the extra args.
fallthru is considering success (ie you won't be denied a git operation on a repo because none of the VREF applied)
If fallthru were to be considered 'failure', you'd be forced to add a "success rule" like this for every vref you used in this repo, in each case listing every user who was not already mentioned in the context of that vref
Considering the update VREF program, you could add a parameter which would allow your update script to recognize it is called in the gitolite-admin context (and should do nothing):
repo gitolite-admin
- VREF/update/donothing = #all
repo #all
- VREF/update = #all

How to let git check for updates on the master server?

I have very poor knowledge about git and would like to ask for help.
I have a linux(-only) application which shall only be "downloaded" (i.e. cloned) with git. On startup, the app shall ask the git "master server" (github) for whether there are updates.
Does git offer a command to check for whether there is an update (without really updating - only checking)? Furthermore, can my app read the return value of that command?
If you do not want to merge, you can just git fetch yourremote/yourbranch, the remote/branch specification usually being origin/master. You could then parse the output of the command to see if new commits are actually present. You can refer to the latest fetched commit as either yourremote/yourbranch or possibly by the symref FETCH_HEAD.
Note: I was reminded that FETCH_HEAD refers to the last branch that was fetched. Hence in general you cannot rely on git fetch yourremote with FETCH_HEAD since the former fetches all tracked branches, thus the latter may not refer to yourbranch. Additionally,
you end up fetching more than strictly necessary.
also refer to Jefromi's answer to view but not actually downloaded changes
the following are not necessarily the most compact formats, just readable examples.
That being said, here are some options for checking for updates of a remote branch, which we will denote with yourremote/yourbranch:
0. Handling errors in the following operations:
0.1 If you attempt to git fetch yourremote, and git gives you an error like
conq: repository does not exist.
that probably means you don't have that remote-string defined. Check your defined remote-strings with git remote --verbose, then git remote add yourremote yourremoteURI as needed.
0.2 If git gives you an error like
fatal: ambiguous argument 'yourremote/yourbranch': unknown revision or path not in the working tree.
that probably means you don't have yourremote/yourbranch locally. I'll leave it to someone more knowledgeable to explain what it means to have something remote locally :-) but will say here only that you should be able to fix that error with
git fetch yourremote
after which you should be able to repeat your desired command successfully. (Provided you have defined git remote yourremote correctly: see previous item.)
1. If you need detailed information, git show yourremote/yourbranch and compare it to the current git show yourbranch
2. If you only want to see the differences, git diff yourbranch yourremote/yourbranch
3. If you prefer to make comparisons on the hash only, compare git rev-parse yourremote/yourbranch to git rev-parse yourbranch
4. If you want to use the log to backtrack what happened, you can do something like git log --pretty=oneline yourremote/yourbranch...yourbranch (note use of three dots).
If you really don't want to actually use bandwidth and fetch new commits, but just check whether there is anything to fetch, you can use:
git fetch --dry-run [remote]
where [remote] defaults to origin. You'll have to parse the output, though, which looks something like this:
From git://git.kernel.org/pub/scm/git/git
2e49dab..7f41b6b master -> origin/master
so it's really much easier to just fetch everything (git fetch [remote]), and then look at the diff/log e.g. between master and [remote]/master.
I'd say git fetch is a potential solution. It only updates the index, not working code. In cases of large commit sets, this would involve a download of compressed files/info, so it may be more than you want, but it is the most useful download you can do.

Resources