Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git: diff between current branch and branch creation

Tags:

git

Imagine this:

git-diff-three-dots

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.

like image 266
guettli Avatar asked Jul 01 '21 08:07

guettli


People also ask

How can I tell the difference between current branch and master?

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 .

How do I compare the differences between two branches in github?

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.


Video Answer


4 Answers

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.

like image 161
matt Avatar answered Oct 19 '22 00:10

matt


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)

like image 42
VonC Avatar answered Oct 18 '22 23:10

VonC


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.

like image 40
jthill Avatar answered Oct 19 '22 00:10

jthill


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

  • list all feature branches in your local clone (except your own branch)
  • look for the "fork point" of your current branch from any of those branches
# 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...
like image 38
LeGEC Avatar answered Oct 19 '22 01:10

LeGEC