2

I have two Git branches, A and B. On branch B I deleted a bunch of files that are in branch A and I also made some changes to existing files in both branches. I want to merge the changes from B into A, but I don't want to delete any files from branch A. Is it possible to do this?

Note that on branch B, I "deleted" the files using $ git rm --cached

What's actually happening:

I have had to deal with this a lot because for a particular project, branch B is my public (published branch) and branch A is a private branch. When I decide to publish branch A, I checkout a new branch B, delete a bunch of private files, and then push that to the public remote.

What ends up happening a lot is that I end up accidentally working off branch B instead of branch A because I forget to switch back over to branch A.

Dom
  • 1,687
  • 6
  • 27
  • 37
Alexander Mills
  • 90,741
  • 139
  • 482
  • 817

2 Answers2

2

You cannot merge branch B into A without also deleting files in A that were deleted in B.

You can check out the individual files, or whole directories from B while on branch A:

git checkout A
git checkout B -- path/to/files/
git commit -m "merged files from B"

This is undesirable in true version control because you won't get the commit history from the B branch; this is just like clobbering a file in there and overwriting everything in its way. You'll have one chunky commit that reflects all changes in the added files.

With a little more work, you can keep the commits if you cherry-pick one-by-one or the range of commits that you're interested in, and ignore the commits that involved deleting files:

git checkout A
git cherry-pick SHA-a-FromB
git cherry-pick SHA-c-FromB..SHA-z-FromB

A further recommendation - dependent on what "private files" you have in B - is to simply ignore them from git. I say this assuming you are dealing with something like a database credentials file, whereby you want to override the production connection with a development database, or vice versa.

In this scenario, I generally have a file such as credentials.inc.php that contains a basic shell for doing stuff like setting up the connection, defining constants, etc. Then in that file, there's a line that reads like this:

if (file_exists(credentials.local.inc.php))
   require_once(credentials.local.inc.php);

Inside credentials.local.inc.php I override all variables with the specific local environment conditions.

Add credentials.local.inc.php to .gitignore and track .gitignore in the repository.

echo "credentials.local.inc.php" >> .gitignore
git add .gitignore
git commit -m "Add credentials.local.inc.php to .gitignore"

Now you're free to merge and publish in any direction, assuring that environment specifics remain in their respective intended locations. If you have default dev credentials, it will always use those unless overridden on a production server with sensitive credentials. If you want to spin up a test, then just append to your local file with the QA credentials.

Community
  • 1
  • 1
Jeff Puckett
  • 37,464
  • 17
  • 118
  • 167
0

Just do the merge --no-commit and whatever git's automerge doesn't do the way you want, fix it.

git merge --no-commit B
git checkout A -- stuff to not/delete
git commit

It's the recorded history that matters, not how you get it.

jthill
  • 55,082
  • 5
  • 77
  • 137