diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 6eb248ef74cae7e139139c9c1756dbe9a6d3f509..50d378335e2ca2c55b172b3926a41f28d4dd6203 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1684,7 +1684,80 @@ void LLAgentWearables::userRemoveAllClothesStep2(BOOL proceed)
 	}
 }
 
-void LLAgentWearables::userRemoveAllAttachments()
+// Combines userRemoveAllAttachments() and userAttachMultipleAttachments() logic to
+// get attachments into desired state with minimal number of adds/removes.
+void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array)
+{
+	// Possible cases:
+	// already wearing but not in request set -> take off.
+	// already wearing and in request set -> leave alone.
+	// not wearing and in request set -> put on.
+
+	LLVOAvatar* avatarp = gAgent.getAvatarObject();
+	if (!avatarp)
+	{
+		llwarns << "No avatar found." << llendl;
+		return;
+	}
+
+	std::set<LLUUID> requested_item_ids;
+	std::set<LLUUID> current_item_ids;
+	for (S32 i=0; i<obj_item_array.count(); i++)
+		requested_item_ids.insert(obj_item_array[i].get()->getLinkedUUID());
+
+	// Build up list of objects to be removed and items currently attached.
+	llvo_vec_t objects_to_remove;
+	for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); 
+		 iter != avatarp->mAttachmentPoints.end();)
+	{
+		LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+		LLViewerJointAttachment* attachment = curiter->second;
+		LLViewerObject* objectp = attachment->getObject();
+		if (objectp)
+		{
+			LLUUID object_item_id = attachment->getItemID();
+			if (requested_item_ids.find(object_item_id) != requested_item_ids.end())
+			{
+				// Object currently worn, was requested.
+				// Flag as currently worn so we won't have to add it again.
+				current_item_ids.insert(object_item_id);
+			}
+			else
+			{
+				// object currently worn, not requested.
+				objects_to_remove.push_back(objectp);
+			}
+		}
+	}
+
+	LLInventoryModel::item_array_t items_to_add;
+	for (LLInventoryModel::item_array_t::iterator it = obj_item_array.begin();
+		 it != obj_item_array.end();
+		 ++it)
+	{
+		LLUUID linked_id = (*it).get()->getLinkedUUID();
+		if (current_item_ids.find(linked_id) != current_item_ids.end())
+		{
+			// Requested attachment is already worn.
+		}
+		else
+		{
+			// Requested attachment is not worn yet.
+			items_to_add.push_back(*it);
+		}
+	}
+	// S32 remove_count = objects_to_remove.size();
+	// S32 add_count = items_to_add.size();
+	// llinfos << "remove " << remove_count << " add " << add_count << llendl;
+
+	// Remove everything in objects_to_remove
+	userRemoveMultipleAttachments(objects_to_remove);
+
+	// Add everything in items_to_add
+	userAttachMultipleAttachments(items_to_add);
+}
+
+void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove)
 {
 	LLVOAvatar* avatarp = gAgent.getAvatarObject();
 	if (!avatarp)
@@ -1693,11 +1766,36 @@ void LLAgentWearables::userRemoveAllAttachments()
 		return;
 	}
 
+	if (objects_to_remove.empty())
+		return;
+
 	gMessageSystem->newMessage("ObjectDetach");
 	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
 	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	
+	for (llvo_vec_t::iterator it = objects_to_remove.begin();
+		 it != objects_to_remove.end();
+		 ++it)
+	{
+		LLViewerObject *objectp = *it;
+		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+		gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
+	}
+	gMessageSystem->sendReliable(gAgent.getRegionHost());
+}
 
+void LLAgentWearables::userRemoveAllAttachments()
+{
+	LLVOAvatar* avatarp = gAgent.getAvatarObject();
+	if (!avatarp)
+	{
+		llwarns << "No avatar found." << llendl;
+		return;
+	}
+
+	llvo_vec_t objects_to_remove;
+	
 	for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); 
 		 iter != avatarp->mAttachmentPoints.end();)
 	{
@@ -1705,12 +1803,9 @@ void LLAgentWearables::userRemoveAllAttachments()
 		LLViewerJointAttachment* attachment = curiter->second;
 		LLViewerObject* objectp = attachment->getObject();
 		if (objectp)
-		{
-			gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
-			gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
-		}
+			objects_to_remove.push_back(objectp);
 	}
-	gMessageSystem->sendReliable(gAgent.getRegionHost());
+	userRemoveMultipleAttachments(objects_to_remove);
 }
 
 void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array)
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index f34b23e2204cc26bc8de6b54265ece7e22869eda..701ce7f05a80445aa7032a70f98d53897ac9b2b6 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -44,6 +44,7 @@ class LLInventoryItem;
 class LLVOAvatarSelf;
 class LLWearable;
 class LLInitialWearablesFetch;
+class LLViewerObject;
 
 class LLAgentWearables
 {
@@ -181,6 +182,11 @@ class LLAgentWearables
 	// MULTI-WEARABLE: assuming one wearable per type.  Need upstream changes.
 	static void		userRemoveWearable(void* userdata);	// userdata is EWearableType
 	static void		userRemoveAllClothes(void* userdata);	// userdata is NULL
+
+	typedef std::vector<LLViewerObject*> llvo_vec_t;
+
+	static void 	userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array);
+	static void		userRemoveMultipleAttachments(llvo_vec_t& llvo_array);
 	static void		userRemoveAllAttachments();
 	static void		userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array);
 
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index dfed1cb57a99f663e2d3d6f33380d2720aab739d..3831846e2e008459caf59ad9f7d7735b65bf316c 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -416,11 +416,11 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory
 
 	if (!append && total_links > 0)
 	{
-		// Remove all current outfit folder links since we're now replacing the contents.
 		for (S32 i = 0; i < cof_items.count(); ++i)
 		{
 			gInventory.purgeObject(cof_items.get(i)->getUUID());
 		}
+		gInventory.notifyObservers();
 	}
 
 	LLPointer<LLUpdateAppearanceOnDestroy> link_waiter = new LLUpdateAppearanceOnDestroy;
@@ -532,19 +532,19 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory
 	const LLUUID &current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
 	// Processes that take time should show the busy cursor
 	//inc_busy_count();
-		
+
 	LLInventoryModel::cat_array_t cof_cats;
 	LLInventoryModel::item_array_t cof_items;
 	gInventory.collectDescendents(current_outfit_id, cof_cats, cof_items,
 								  LLInventoryModel::EXCLUDE_TRASH);
-
+	
 	if (items.count() > 0)
 	{
-		// Remove all current outfit folder links since we're now replacing the contents.
 		for (S32 i = 0; i < cof_items.count(); ++i)
 		{
 			gInventory.purgeObject(cof_items.get(i)->getUUID());
 		}
+		gInventory.notifyObservers();
 	}
 
 	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
@@ -696,21 +696,11 @@ void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder,
 		}
 	}
 
-
-	//If the folder doesn't contain only gestures, take off all attachments.
-	if (!(wear_items.count() == 0 && obj_items.count() == 0 && gest_items.count() > 0) )
+	// Update attachments to match those requested.
+	LLVOAvatar* avatar = gAgent.getAvatarObject();
+	if( avatar )
 	{
-		LLAgentWearables::userRemoveAllAttachments();
-	}
-
-	if( obj_items.count() > 0 )
-	{
-		// We've found some attachments.  Add these.
-		LLVOAvatar* avatar = gAgent.getAvatarObject();
-		if( avatar )
-		{
-			LLAgentWearables::userAttachMultipleAttachments(obj_items);
-		}
+		LLAgentWearables::userUpdateAttachments(obj_items);
 	}
 }