Search code examples
gitbranchgit-rebasefeature-branch

Show commits affecting a file that are not in a feature branch?


Given branch-a and git rebase origin/master branch-a, sometimes you get conflicts in a file.

CONFLICT (content): Merge conflict in .../file.txt

Given that before the rebase there were no conflicts (by definition), then conflicts can only have occurred b/c one or more commits to .../file.txt.

During the conflict resolution process, I can't figure out a way to easily show "commits from origin/master that affected .../file.txt" so that I can more confidently integrate those changes.

---A---B---[C]---D
    \             \
     E---[F]---G   E'--[C/F']--G'

ABCD is mainline development. EFG is my local branch development. Commit C caused a conflict in file/commit F during my local rebase onto D.

Given a detached HEAD or "rebasing" state, when I do git log -3 file.txt it doesn't seem to show me what I want to see, which is WHAT was the diff (ie: commit C) which caused the conflict I'm trying to resolve now when applying commit F.

How can I get a list of commits which only affect a particular file and are from the range ABCD... not including my commits in EFG or the currently active --rebase?


Solution

  • You should get the output you need with:

    git log --patch --full-history A..D -- file.txt
    

    The --patch (or -p) flag is probably the main thing you're looking for: it shows the diff for each commit logged.

    The --full-history flag prevents Git from simplifying the history by omitting commits based on the current status of the worktree. This may not be necessary depending on your specific situation.

    The A..D limits the output to commits between commit A (exclusive), and commit D (inclusive). This is probably a more reliable way to limit the commits instead of -3, assuming you have the refs for A and D handy. And actually, you will always both refs handy, because D is the tip of your mainline branch, and you can get A by doing:

    git merge-base <mainline> <local>
    

    A concrete example:

    Assume that the mainline branch is master, and the other branch is feature.

    git rebase master feature
    # conflicts occur
    git log --patch --full-history $(git merge-base master feature)..master -- file.txt
    

    To save time, you could also set up an alias:

    git config --global alias.conflict-commits "! git log --patch --full-history $(git merge-base $1 $2)..$1 -- $3"
    

    Then use it as:

    git conflict-commits master feature file.txt