git for-each-ref equivalent in GitPython? - gitpython

I would like to iterate over all the references using the GitPython API, in the same way git for-each-ref does it. How can I do that ?

On a repository created with
import git
r = git.Repo('.')
the r.refs data member is a list of all the references, as it would be returned by git for-each-ref (see http://gitpython.readthedocs.org/en/stable/reference.html#git.repo.base.Repo.refs for more information).

Related

Do *not* show pgp signature in git log

The git log subcommand has the option --show-signature to display pgp signatures of the commits (if present).
This can also be enabled by default via git config log.showSignature true.
I have set this config option to true.
The problem is that I am now looking for an option to pass to git log to not show the signature in the log (while the config is still set to true),
something like
git config --no-show-signature.
I was unable to find anything helpful in the git documentation.
For context: Most of the time, I do want git log to be active, but in some automated scripts, I really don't need this, because it messes up some automatic parsing etc.
I'll repeat #phd's comment, which in the current state of things seems like the most straightforward way to cancel that config parameter (and only that one) :
Try git -c log.showSignature=false log
Another option is to use git log's sister command : git rev-list.
The differences are :
git rev-list isn't affected by log.* config parameters
you need to add --no-commit-header to avoid one extra line on each commit (see this answer here which links to doc)
you need to specify explicitly the refs/branches names (e.g: git rev-list will error, you need to say git rev-list HEAD)
Other than that, it understands the same options as git log :
git rev-list --no-commit-header --graph --format="%h (%an %ad) %s" HEAD

Git alias for checkout branch, pull and checkout back

We are using the Feature-Branch-Workflow, which means others merge theire changes to the dev-branch that I want to merge into my feature branch. As it happens a lot I would like to have a simple git alias which does:
Checkout the dev branch
Pull
Checkout the previous branch
I want to do the merge myself, as sometimes changes block the checkout or pulls can fail.
My current state is:
[alias]
pull-and-back = !git checkout $1 && git pull && git checkout #{-1}
which sadly gives the error error: pathspec 'dev' did not match any file(s) known to git.
What is going wrong? I assume as the exclamation mark causes the command to be interpreted as bash code the last part #{-1} is not evaluated by git but by bash instead.
You'd have to use an ad hoc bash function to pass your parameter :
git config alias.pab '!f() { git checkout $1 && git pull && git checkout -; }; f'
As a note, git checkout - is a handy shortcut for git checkout #{-1}, but both work.

How I cherry pick previous branch's latest commit by one command?

For example, I have branch "feature-A".
Then I execute one commond that can help me checkout to "feature-B" and cherry pick "feature-A"'s lastest's commit.
Does git have such a magical command? Or does anyone have a ready-made script? If so, this could save me a lot of time.
Thanks!
You can concatenate 2 git commands: first to move to your desired branch (in this case feature-B) and then cherry pick the last commit on the top of your other branch (in this case feature-A)
You can do it by running git checkout feature-B && git cherry-pick feature-A
Remember you can specify -n after cherry-pick if you don't want to commit (so you can check it before committing), or on the other hand you can concatenate && git push in case you don't need to check but you want directly to push everything in the same command after the cherry pick.
Below bash/zsh script might help if you want to cherry-pick only the latest commit from feature-A
git checkout feature-A
commitId=$(git log -n 1 --pretty=format:"%h")
git checkout feature-B
git cherry-pick $commitId
git diff --stat --cached origin/feature-B
Then to push the changes, run below command
git push origin feature-B

Git filter-branch to filter-repo : tags not rewritten

I've been trying to modify a script using git filter-branch that takes a git repository and separates it in multiple new directories by specifying subfolders of this directory. The new directories should only have the commits that modified their corresponding subfolders, hence the use of filter-branch.
My goal being to change filter-branch by filter-repo for better performances.
It used to create a new branch $branch then use this command :
git filter-branch -f --prune-empty --tag-name-filter cat --subdirectory-filter $subdir $branch --tags
Followed by this to push the branch to its corresponding repo (which has the same name) as well as the rewritten tags :
git checkout $branch
ssh-agent bash -c "ssh-add ../$privateKeyName; git push $branch $branch:$branchToExtract --tags -f"
($branchToExtract is not important, you may just consider it to be "master")
So, as said before, I've been trying to use filter-repo instead of filter-branch. This is the command I've been using :
git filter-repo -f --prune-empty always --subdirectory-filter $subdir --refs $branch
And it works fine ... Except for one (important) thing : when pushing everything to the new repos, the tags are the same that the main original repo, which means that they have way too much content (and commits) and not what they should have. It's like the tags aren't being rewritten at all.
I've been trying a few different things like --tag-rename but to no avail.
Any help as to what I should do or indication about what I may be doing wrong would be really appreciated. Thanks :)
As stated by LeGEC, listing the tags in --refs solved the problem. I didn't fully realize how the option works.
To anyone interested, this mean the correct command is
git filter-repo -f --prune-empty always --subdirectory-filter $subdir --refs $branch $(git tag -l)

Display detached heads elegantly in CLI

I'd like my commandline (PS1 variable) to display detached heads more elegantly, even if it's a little more ambiguous. The reason I want to do this is because while I never work on detached branches, I frequently encounter them due to our project setup, and want to know what branch they were from (or at least, a branch that they are on).
First of all, I believe I have a sound understanding of the difference between:
The head commit of master
A detached head, which happens to be the same as the head of master
That's the difference between these two commands:
git checkout master # Checkout the master branch
git checkout master~0 # Checkout the commit from the head of the master branch
Now onto the problem. At the moment, my PS1 contains $(__git_ps1) at the end, and commandline shows this as a result:
# git checkout master~1
addison:~/project ((111abcdef1...))$
# git checkout master~0
addison:~/project ((000abcdef0...))$
# git checkout master
addison:~/project (master)$
What I want to happen, is if I'm on a detached head, to be able to find a branch which has a matching commit hash (prefer master), and display the branchname, and how far behind HEAD the commit is, like this:
# git checkout master~1
addison:~/project (Detached(master~1))$
# git checkout master~0
addison:~/project (Detached(master))$
# git checkout master
addison:~/project (master)$
I understand that there may not be a utility that does this already, and I'm ready to accept that - If that is the case, I'd like to know how I can go about finding a branchname for a commit hash, and how far behind the branch's HEAD commit it is. I know that there may be multiple branches that have a commit with the same hash - I just want a 'best effort' solution. That might mean just choosing the most recent, or the closest to HEAD, etc.
Using this information, I can make my own script and embed it in my $PS1 variable, and format it exactly how I want.
UPDATE
I found out there is an option that can be set with $(__git_ps1), which can change the format of the output to be exactly how I want:
GIT_PS1_DESCRIBE_STYLE=contains # git describe --contains HEAD
GIT_PS1_DESCRIBE_STYLE=branch # git describe --contains --all HEAD
GIT_PS1_DESCRIBE_STYLE=tag # git describe --tags HEAD
GIT_PS1_DESCRIBE_STYLE=describe # git describe HEAD
GIT_PS1_DESCRIBE_STYLE=default # git describe --tags --exact-match HEAD
If I set the option to branch, then the output is much more readable.
As you've noted, there isn't a perfect solution. There are two approaches that Git itself uses. One is exemplified by git status: when you're on some branch, HEAD contains the branch name, and when you're detached, HEAD contains a hash ID, but the reflog for HEAD still has the branch name in it, and Git can scan that and pick out a recent branch and see if you're on that commit or one of its descendants and say detached at name or detached from name.1
In your case, though, you might want something more like what git describe does, only in the order that's not the default for git describe. In this case, what you want is more like what git describe --contains does. The --contains option implies the --tags option, which has git describe look at all tags, but not look at any branch names. Fortunately, you can add --all:
git describe --contains --all
which looks at tag and branch names—and other references too, including refs/stash, which may not be so great—and picks one of those to describe the current commit. So this may be the closest thing Git has built in to what you want.
1This feature was not in some very old versions of Git. I'm not sure when it first appeared, and the release notes only mention it in describing a fix to Git 2.4.0. Before 2.4.0, git branch and git status disagreed in when and how they said "detached at" vs "detached from". So it's in 2.4 and later, but earlier versions are less good at it, and at some point, the "detached at/from" stuff just isn't there at all.

Resources