Imagine this:
I created the branch "B" three days ago. It is the branch I am currently working on. Now I want to know what changed since the branch was created (X
).
This gives my a diff between B and X (like the dashed line in the picture):
git diff A...
Above command is handy, since it is short and I don't need to remember "X".
But: I am super lazy. I don't want to remember which branch my current branch was created from.
How can I avoid to remember/type A
?
I am looking for a way which needs no input from my side. It should list all changes since the last time a branch was created.
git diff origin/master... This shows only the changes between my currently selected local branch and the remote master branch, and ignores all changes in my local branch that came from merge commits. For reference, if you need the commit refs of commits that contain these changes, use git cherry origin/master .
On the Github, go to the Source view of your project. You will see a link named 'Branch List'. Once the page opens you can see a list of all the remote branches. Hit on the Compare button in front of any of the available branches to see the difference between two branches.
Well, @{-1}
might be A. But then again it might not. It simply means "the branch I was on previously". Similarly, looking through the git reflog
might tell allow you to deduce where you were when you created the current branch.
But there is nothing about the current branch itself that tells you any of that. The real problem here is that you have a different idea of what a "branch" is than Git does. The phrase "since the branch was created" is probably misleading you.
You seem to think that B is "everything since X, up to the end of B." It isn't. B is just one commit: the one labelled B in your diagram. Everything else backwards from that — the commit before B, and the commit before that, and X, and the commit before X, and the commit before that, backwards all the way to the root commit — have exactly the same status. They are commits reachable from B, and that is all they are.
So there is nothing special about X in Git's mind. You think it is special because it is where A and B "meet". But to distinguish that fact you must know the names of B and A. You are seeing a topology that depends upon A; you must communicate what you see to Git if you want Git to help you.
Once you are willing to talk about both A and B, then fine, you can ask for git diff ...A
and git diff A...
to find out what changed since X. Or you can talk about git merge-base A B
to find X. But only a human being can distinguish that the key here is A.
But: I am super lazy. I don't want to remember which branch my current branch was created from.
Then you need to script it, in an executable called git-diffca
, which can then be called as git diffca
(ca for "common ancestor")
In that script, you need to decide what criteria you want to chose amongst all the candidate branches:
c--c--c (C)
/
a--Y--X--a--a (A)
\
b--b--b (B, HEAD)
What do you want to look at: changes from Y
(a common ancestor between branch C
and B
)? or from X
(between A
and B
)
I would look at all branches, compute git merge-base <aBranch> B
for each one, and take the most recent commit (X
in the case of the schema)
Then the script would display git diff A...
(since git merge-base A B
yielded the most recent common ancestor with B)
I don't want to remember which branch my current branch was created from. How can I avoid to remember/type
A
?
Tell Git to track it for you. To make this happen, when you want to branch off your current checkout, add the t
option:
git checkout -tb B
will switch to a new branch B
tracking your existing ... whatever branch, A
, right? Notice I didn't have to remember or type it. See the git branch -u
option for setting a new upstream after the fact.
When you've told git what branch you're tracking, git diff @{u}...
or git diff @{upstream}...
does exactly what you want. You could even make it an alias, git config --global alias.du diff @{u}...
.
Note that Git ordinarily sets up tracking on upstream branches from remotes automatically: if you say git checkout fix32943
and you don't have a fix32943
branch and there's exactly one remote with a fix32943
branch, Git will make a local fix32943
branch and set it up, as if you'd done the above because that's exactly what it's doing for you, to track that upstream. So git diff @{U}...
often already works the way you want it to.
I will repeat what @matt has amply detailed in his answer : git
tracks commits, but not branches
There is however something that looks like "the life of that branch", it's the reflog for that branch :
git reflog my/branch
You can inspect the history and see if you find any information there.
For example : the commit when the branch was created would be :
git reflog my/branch | tail -1
# and use something like `| awk '{ print $1 }'` for the sha,
# or parse the 'branch: Created from ...' message (if there is one)
# to see if there is a branch name
git reflog --format="%H" my/branch | tail -1 # if you want only the sha
But again, there are caveats : if you have run git rebase
during the lifetime of the branch, then the initial commit is probably not the fork point you are looking for anymore.
Another proxy could be : look at the commits that are in the history of branch B
, and in the history of no other branch :
# the following will list all branches except 'my/branch' :
git branch --format="%(refname:short)" | grep -v "my/branch"
# here is a way to list all commits on 'my/branch', excluding commits
# from all other branches.
# Adding `--boundary` will also display the first 'hidden' commit
git log --boundary --oneline --graph my/branch --not $(<the command above>)
# you can also replace 'git log' with 'git rev-list', if you only want the hashes
With some luck, the commit mentioned as a boundary is the one you are looking for.
The caveats being : if there are some merges in the history of your branch, you may have several "boundary" points, and if there is another branch that "forked off" from B more recently than the X
you are looking for, then the boundary would be the fork point with that branch, and not with master
or develop
.
update based on your comment : you can
# get the name of your current active branch :
mybranch=$(git rev-parse --abbrev-ref HEAD)
# make a separate function to list on stdout "all the branches except mine"
list_branches () {
# list the `master` branch
echo "master"
# get all 'origin/somefeature' branches, excluding mybranch
# suggestion: list remote branches (you will get all features,
# even if you haven't created a local checkout of a branch)
git branch -r --format="%(refname:short)" |\
grep "/feat/" |\ # you can grep for a pattern if you have one
grep -b "$mybranch" # remove your branch from the lot
}
# get the 'boundary' commits of your branch with respect to
# all the other branches
base=$(
git rev-list --boundary --graph "$mybranch" --not $(list_branches "$mybranch") |\
grep -e "^-" |\ # rev-list will prefix boundary commits with a '-'
tail -1 |\ # if there are several, only take the last one
tr -d '-' # delete that leading '-'
)
# with some luck, we computed the correct base commit :
git diff $base...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With