How can I get tracking information (i.e. remote and branch name) about a specific local Git branch, preferably in one command? There seem to be many ways to do this, e.g.
git rev-parse --abbrev-ref --symbolic-full-name branch_name#{upstream}
However, it returns the upstream in the form 'origin/branch_name', which makes it difficult to figure out the separate parts (e.g. when remote or branch name contains '/'). Is there more reliable solution, preferably using a single Git command?
#RomainValeri in the answer suggested this command to display the tracking information.
git for-each-ref --format="%(upstream:short)" refs/heads/<yourBranch>
However, if you want to get rid of the slash then you can do this
git for-each-ref --format="%(upstream:remotename) %(upstream:lstrip=-1)" \
# Insert your separator here ^
refs/heads/<yourBranch>
From git-docs,
upstream
The name of a local ref which can be considered “upstream” from the
displayed ref. Respects :short, :lstrip and :rstrip in the same way as
refname above ...
For any remote-tracking branch %(upstream), %(upstream:remotename) and
%(upstream:remoteref) refer to the name of the remote and the name of
the tracked remote ref, respectively. In other words, the
remote-tracking branch can be updated explicitly and individually by
using the refspec %(upstream:remoteref):%(upstream) to fetch from
%(upstream:remotename).
More on lstrip,
If lstrip= < N > (rstrip= < N >) is appended, strips < N > slash-separated
path components from the front (back) of the refname (e.g.
%(refname:lstrip=2) turns refs/tags/foo into foo and
%(refname:rstrip=2) turns refs/tags/foo into refs). If < N > is a
negative number, strip as many path components as necessary from the
specified end to leave -< N > path components (e.g. %(refname:lstrip=-2)
turns refs/tags/foo into tags/foo and %(refname:rstrip=-1) turns
refs/tags/foo into refs). When the ref does not have enough
components, the result becomes an empty string if stripping with
positive < N >, or it becomes the full refname if stripping with
negative < N >. Neither is an error.
Some examples :
Format : "%(upstream:remotename):%(upstream:lstrip=-1)"
Output : <remote-name>:<branch-name>
Format : "%(upstream:remotename) %(upstream:lstrip=-1)"
Output : <remote-name> <branch-name>
If the branch name includes a slash, then lstrip won't work. Instead remoteref can be used.
git for-each-ref --format="%(upstream:remotename) %(upstream:remoteref)" refs/heads/<yourBranch>
The output is in this format : <remote-name> refs/heads/<branch-name>
To remove refs/heads/ from the output, pipe the above command to this
sed 's/refs\/heads\///g'
I'd use the built-in -v (verbose) or even -vv (very verbose) flag to get this from git branch output. You might also just grep the branch name to focus on what you wanted :
git branch -vv | grep <branchName>
Depending on what exactly you want to get, maybe also consider using the plumbing tool :
git for-each-ref --format="%(upstream:short)" refs/heads/<yourBranch>
and make it an alias for convenience
git config --global alias.get-rem '!f() { git for-each-ref --format="%(upstream:short)" refs/heads/$1; }; f'
# then just
git get-rem branch_name
Edit : For the very short part (i.e. "branch" instead of either "refs/remotes/origin/branch" or even "origin/branch"), you can use %(upstream:lstrip:-1) instead of %(upstream:short)
Related
trying to get only one result from selected commits returns the same output regardless of
output order.
TOTAL LIST LENGTH 130 COMMITS
The result is the same, but the list is different
showing reduced results :
$ git rev-list --reverse origin/a..origin/b -10
c4fe26e8ebc8a2ceb0129a6f7318b08d18126baa
fd302babdae3338a2d780b529ec8499867d1c330
d24b219372ff87ada2c196857f47f7a9c61f1fad
1eaf20b79e69ae4d729a2679bdc40f6b2d22958f
6a76950fd9eee705ed813aec0c44ac58ff3a030c
058e793dbcd507861880b21aacf2dd07d2b079ff
f8bb9225c4101bf1340e35abd609e526d2bde2c1
a01e72042582337ff74f64caa0e5a25ceeba6c8d
bc88772e4cb3be926639da6d71a57aaef507cbf0
315f11516b98454cb8732ac57b9cc53dff9460b5
$ git rev-list origin/a..origin/b -10
315f11516b98454cb8732ac57b9cc53dff9460b5
bc88772e4cb3be926639da6d71a57aaef507cbf0
a01e72042582337ff74f64caa0e5a25ceeba6c8d
f8bb9225c4101bf1340e35abd609e526d2bde2c1
058e793dbcd507861880b21aacf2dd07d2b079ff
6a76950fd9eee705ed813aec0c44ac58ff3a030c
1eaf20b79e69ae4d729a2679bdc40f6b2d22958f
d24b219372ff87ada2c196857f47f7a9c61f1fad
fd302babdae3338a2d780b529ec8499867d1c330
c4fe26e8ebc8a2ceb0129a6f7318b08d18126baa
$ git rev-list --max-count=1 origin/a..origin/b
315f11516b98454cb8732ac57b9cc53dff9460b5
$ git rev-list --reverse --max-count=1 origin/a..origin/b
315f11516b98454cb8732ac57b9cc53dff9460b5
List commits that are reachable by following the parent links from the
given commit(s), but exclude commits that are reachable from the
one(s) given with a ^ in front of them. The output is given in reverse
chronological order by default.
the command i use
git rev-list --max-count=1 $TARGET_BRANCH..$BASE_BRANCH
from documentation
Note that these are applied before commit ordering and formatting
options, such as --reverse.
-
-n
--max-count= Limit the number of commits to output.
using the following git version
git version 2.39.0.windows.1
The cited section from the documentation explains that the meaning of
git rev-list --max-count=1 --reverse $TARGET_BRANCH..$BASE_BRANCH
is:
Collect commits in the range $TARGET_BRANCH..$BASE_BRANCH in the usual way.
Truncate the collect list after the first entry (--max-count=1).
List the remaining commit in reverse order (--reverse).
Of course, if the list has only one entry, the printed result looks the same regardless if printed forward or in reverse.
As the docs you link say, git rev-list's --max-count is applied very early, before --reverse.
To get the effect you're asking for, use existing tools. git rev-list origin/a..origin/b | tail -1 to get the last entry.
In a git branch I store the latest commit hash SHA using
latest_sha=$(git log --pretty=oneline | head -1 | cut -d ' ' -f 1)
After a bunch of commits in this branch, how do I get the next commit SHA after the latest_sha.
Say if there are 5 commits made to this branch after the $latest_sha.
I want to always get the SHA of the first commit after the latest_sha.
b8eead8ba4ff375911af6
c2452680eb7731e4d36ca
da2e113ca4768f5f34730
95b98d42a6e567ed56fc2
716c4f84a855f48bee55c
6a7223a74269f925cfd9e---I need this one
e945bcfabf3fbafc85084---latest_sha
159df375376ded565bec0
d725350982626f46a8b80
56a4b6ca91d93acc8d751
de584608616b1ed99a554
3cfc15339a98bb286d5baa
6ae834bf36c90fbd81854
fa9bdebd0f814f04ee05ba
cc44c4d9ff14314c1255da
5a6145586a8fdcaa2da659
bfea8cfe121d24a0ff1525
Thanks!
A Git branch name, in a sense, is the latest hash ID. That is, if git log branchX shows you commit b8eead8ba4ff375911af6 first, then branchX is a name representing b8eead8ba4ff375911af6, and:
git show branchX
will show the same commit as:
git show b8eead8ba4ff375911af6
If you need the hash ID for some reason—e.g., because you're going to change the hash ID to which the branch name points, by adding new commits—the simplest command to get it is git rev-parse:
hash=$(git rev-parse refs/heads/$branch)
For the rest, see alfunx's answer. Note that if the commits form a diamond-shaped graph, e.g.:
I--J
/ \
...--G--H M--N <-- branchX
\ /
K--L
then there are two commits that immediately follow H, but either I nor K are ancestors of each other, they're only related by both being descendants of H and ancestors (grandparents, in this case) of merge commit M. Using git rev-list --ancestry-path ^<anything-identifying-H> <anything-identifying-branchX> will list commits I, J, K, L, M, and N. The listing will start at N and move back to M as its second entry, but at this point, Git now has a choice of whether to list J or L. This is where the sorting options you choose go into effect. The default sort is chronological by committer date-and-time stamp.
Having listed either J or L, Git can now list the parent of whichever commit it listed, or the remaining commit on the other fork of history. Git will list one of them. If it chose to list J first, then I, it must now list L and then K in that order; if it chose to list L first, then K, it must now show I and then J in that order. But it might also list them in the order J, L, K, I, for instance; or J, L, I, K. Adding --topo-order constrains git rev-list to avoid interleaving commits from the two legs.
The linearization order in complex graphs is generally problematic: there's no single solution that handles all cases. That's why git rev-list offers multiple sorting options.
You could do that with rev-list:
git rev-list --ancestry-path HEAD ^${latest_sha} | tail -n1
rev-list lists all reachable commits in reverse chronological order for the given branches/commits. The caret (^) here means "not", which makes Git exclude all reachable commits starting at the given commit.
Concretely that means: Include all commits reachable from HEAD, exclude all commits reachable from ${latest_sha}, and then take the oldest one there using tail.
Edit: Add --ancestry-path to make sure only commits that are in the direct ancestry path between the specified commits are used (as mentioned by #jthill).
git logs have a parent commit field, so you could do something like
git log --pretty=format:"%P %H" | awk '$1 == "<YOUR_HASH>" {print $2}'
I want to extract the number of latest version of a Git repository. This what I've done so far:
#--- Checking out latest tag
printf "%bChecking out tag...%b\n" "${YELLOW}" "${GRAY}"
LATEST_TAG=$(git describe --tags)
printf "\nChecking out tag %b${LATEST_TAG}%b\n" "${YELLOW}" "${GRAY}"
git checkout -b V${LATEST_TAG%-*} ${LATEST_TAG}
My problem is that if git describe --tags returns something like this 1.0.0-39-gf8f8306 I end up creating a branch V1.0.0-39.
What I want is to create a branch named V1.0.0.
It’s a bit of a secret,* but you can use --abbrev=0:
git describe --tags --abbrev=0
*git help describe mentions it, but you have to know where to look:
--abbrev=<n>
[…] An <n> of 0 will suppress long format, only showing the closest tag.
You can use awk:
LATEST_TAG=$(git describe --tags | awk -F - '{print $1}')
In your line
git checkout -b V${LATEST_TAG%-*} ${LATEST_TAG}
you can double up the % symbol which will match the longest string starting with a - rather than the shortest which is what a single % does.
eg git checkout -b V${LATEST_TAG%%-*} ${LATEST_TAG}
You can see a full list of parameter expansions here: http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion
I had an issue with git describe on GitHub Actions, namely: "fatal: No tags can describe '160ef4560d8855c9c05f4cae207baeb71b7791f3'." Which apparently has something to do with the entire repo not being available.
But I found another solution that works and doesn't have this issue:
git tag --sort=-refname --list "v[0-9]*" | head -n 1
What mistake am I making in the steps I'm following?
I've edited files in repo Alpha on my local box. I then realized I wanted those changes in a different repo Bravo that is also on my local box. I tried this:
c:/repos/alpha/>git diff --cached > mypatch.txt
I then copy the patch file to the other repo location and type this:
c:/repos/bravo/>git apply mypatch.txt
If the shell I used for the diff and apply was powershell or "Git CMD", then the second command makes the error:
fatal: unrecognized input
If instead I use the "Git Bash" shell to execute the two commands, then I get a different error:
5109e.patch:19: trailing whitespace.
IL.DataUsageGB,
warning: 1 line adds whitespace errors.
I then try to apply the changes more carefully with the following command:
$ git apply --reject --whitespace=fix mypatch.txt
From this I get a dump of numerous errors. Example:
error: while searching for:
);
GO
-- Anchor table ------------------------------------------------------------
-------------------------------------------
-- IL_InvoiceLine table (with 33 attributes)
----------------------------------------------------------------------------
-------------------------------------------
IF Object_ID('dbo.IL_InvoiceLine', 'U') IS NULL
CREATE TABLE [dbo].[IL_InvoiceLine] (
error: patch failed: scripts/bi/sql/Unified_ODS_Schema.sql:302
The branch in repo Alpha and the corresponding branch in repo Bravo both come from the same origin and both have a git status that report "up to date" with the upstream. In other words, the branches are identical except for the staged changes that exist on Alpha. I am expressly avoiding a push/pull with the origin.
Suggestions?
TL;DR
There's nothing wrong, and you can completely ignore the warning. You don't need --reject or --whitespace=fix, but if you do want to use the latter, use it without the former.
Longer
If the shell I used for the diff and apply was powershell ...
This winds up writing the output as Unicode (through some mechanism I cannot describe properly since I don't "do" Windows). You'd have to filter that back to UTF-8 or ASCII to get it to apply.
If instead I use the "Git Bash" shell to execute the two commands, then I get a different error:
5109e.patch:19: trailing whitespace.
IL.DataUsageGB,
warning: 1 line adds whitespace errors.
That's not really an error, that's a warning. It means that your original patch adds a blank before an end-of-line. By default, git apply calls this an "error" but it really means "warning". It's meant to alert you to the fact that there's an invisible character on the line(s) in question, which you may not have intended. (Or maybe you did! For instance, in some Markdown formats, ending a line with two blanks inserts a paragraph break. See aslo Git ignore trailing whitespace in markdown files only.)
What constitutes a "whitespace error" (which really should be "whitespace annoyance" or "whitespace warning" or "whitespace glitch" everywhere, rather than "error") is configurable. By default git diff will highlight such whitespace glitches. While I cannot quite show it here, imagine the - line is in red and the + line is in green and that <space> represents a trailing blank:
- blah blah
+ blah foo blah<space>
This space would be highlighted in red, to make it stand out as a "whitespace error" (which I would call a whitespace glitch or annoyance or warning, but as long as we are using Git we should understand what the phrase "whitespace error" means here).
With --whitespace=fix, git apply will find the things it considers to be whitespace errors and determine whether it can fix them automatically by:
stripping trailing whitespace
removing some space-before-tab spaces
fussing with CRLF vs LF-only
If it can fix them, it will. This includes applying the patch even if the context does not quite match up but can be made to do so by this kind of fussing, so it's more than just "removing trailing whitespace in the added lines".
I'm writing a script to analyze changes have been made into a git repo.
At some point I need to iterate over all the commits and obtain these information about each of them:
Commit ID
Date
Commit Message
...
Files changed
File Name
Type of change (Added/Modified/Removed/Renamed)
New File Name (in case the change type is "Renamed")
Number of lines added
Number of lines removed
I get the commit messages and dates by git log. The issue I have is with the files.
If I don't want to collect number of lines added/removed, I'd simply use
git diff-tree --no-commit-id --name-status -M -r abcd12345
The output would be something like
A Readme.md
M src/something.js
D src/somethingelse.js
R100 tests/a/file.js tests/b/file.js
Which I can parse and read programmatically.
To get information about lines added/removed, I could use this:
git diff-tree -M -r --numstat abcd12345
The output would be like:
abcd12345
82 0 Readme.md
41 98 src/something.js
0 64 src/somethingelse.js
0 0 tests/{a => b}/file.js
Which is not that machine readable for renamed files.
My question is: Is there any way to combine these two commands? It seems I can't use --numstat with --name-status.
I can run two separate command and merge the result in my script as well. In that case, is there any other switches that I can use to make the result of the second command more machine readable?
Thanks.
I think your analysis (that you need two separate commands) is correct. Use -z to obtain machine-readable output with --numstat (this disables both fancy rename encoding and all special-character-quoting), but note that you will then have to break lines apart at ASCII NULs instead of newlines.