Sam R.
Sam R.

Reputation: 16450

How to create a git branch with custom diff to master branch?

Sorry for the vague question title, I don't know how to phrase it better. Basically I have a master branch with two commits c1 and c2:

    +-----> dummy1   +-----> dummy2
    |                |
    |                |
    |                |
    |                |
  c1+              c2+
   .                 .
   └── a.txt +       ├── a.txt
                     ├── b.txt +
                     ├── not-wanted.txt +
                     └── c.txt +

c1 has added a.txt file. c2 has added three more files as you see. Now I wanna have two dummy branches, one off of c1 and another from c2 so that when I do git diff dummy1..dummy2 I only see the file b.txt and c.txt in the diff. So the resulting PR between dummy1<-dummy2 only shows b.txt and c.txt but not the not-wanted.txt.

Is this possible?

Upvotes: 0

Views: 332

Answers (3)

torek
torek

Reputation: 487755

TL;DR: you'll need some new commits. You can't get what you want with your existing commits.

Long

Git isn't about branches or files: Git is all about commits. Pull requests2 use branch names, but only so that Git can find commits.

In other words, everything is always about commits. Names—branch names like master or develop, or tag names like v2.1, or remote-tracking names like origin/master, or even pull requests on GitHub—really just identify one specific commit. Each commit holds files—a complete snapshot of all files, in fact—along with metadata like who made it (user name and email address), when (date-and-time-stamp), and why (log message).

The fact that there's more than one commit in a branch, or in a pull request, occurs because each commit records its parent commit, by hash ID. Every commit has its own unique hash ID, and every commit1 says ... and if you want to know what comes before me, look to commit XXXXXX, where the Xs are the previous commit's hash ID.

So, in your setup, you have a series of commits on your master that either ends at c2 or goes on further:

...--B--c1--c2--D--E--F--G   <--master

Someone else might have a series of commits, in their repository, that ends at B. If so, you can make a name that points to c1, giving you:

...--B--c1   <-- name1
          \
           c2--D--...--G   <-- master

If you now make a pull request to someone else using name1, you're asking that someone else—whose chain of commits ends at B—to copy your commit c1 into their repository, and set some name of theirs to point to c1.

You can also make a name pointing to c2:

...--B--c1   <-- name1
          \
           c2   <-- name2
             \
              D--...--G   <-- master

and make a pull request using your name2, which asks that someone to incorporate both c1 and c2 into their repository and set one of their names to point to c2.

No matter what you do, you're always going to be asking them—whoever they are—to take their branch-name that points to existing shared commit B, which is already in their repository as well as in yours, and add new commits on to the end of their commit B. What you control is which specific commit you ask them to use. They will take every commit from their end—their copy of B—to this new tip commit. So you can make a new commit, let's call it c3, that comes after c1, that you remember via branch name name3:

           c3   <-- name3
          /
...--B--c1--c2--D--E--F--G   <--master

This commit c3 has whatever contents you like. You then send them a pull request asking them to set their master (or whatever other branch name) so that instead of pointing to shared commit B, they copy commits c1 and c3 into their repository and then set their name to point to c3.

To do that:

$ git checkout -b name3 <hash-of-c1>
... make whatever changes you like, e.g., git cherry-pick -n <hash-of-c2>
... fix things up, git add files as needed ...
$ git commit

to create new commit c3 to which your branch name name3 will point. Then you can make a pull request using this name3 name and new c3 commit.


1At least one commit in every non-empty repository has no parent: that's the very first commit, which has no previous commit because it can't. Some commits have two, or possibly even more, parents: these are merge commits. Most commits just have one parent, though. Git's history is the commits, strung together using the backwards-looking chain formed by working backwards from the last commit, found by some branch name, one commit at a time (or two or more when reaching a merge).

2Pull requests are not actually part of Git itself: they're add-ons, provided by places like GitHub and Bitbucket. What Git provides are the commits themselves and methods—git fetch and git push—for receiving and sending commits between peer repositories. Before GitHub, people would clone a Linux repo, make new commits, and then email patches around for review and revision ... and in fact, they still do that.

Upvotes: 2

Kshitij Jain
Kshitij Jain

Reputation: 136

Since you don't want not-wanted.txt to show up, it looks like you need to create a new commit after deleting not-wanted.txt.

Delete not-wanted.txt
git commit -m "c3"

Now create the two branches from c1 and c3

git branch dummy-1 c1
git branch dummy-2 c3

If you also want not-wanted.txt file to be backed up in some branch, you can create branch at c2:

git branch backup-branch c2

Upvotes: 2

zwbetz
zwbetz

Reputation: 1100

No need to create separate branches. You can diff between commits in your current branch:

git diff c1 c2

Then, if needed, use the diff to create a patch: How to see the changes between two commits without commits in-between?

Upvotes: 1

Related Questions